1. link 和 script 里的路径就不用说了
2. 更改全局变量
mxBasePath = "/static/js/conceptualModel/js/mxgraph/";
STYLE_PATH = "/static/js/conceptualModel/styles";
RESOURCES_PATH = "/static/js/conceptualModel/resources";
IMAGE_PATH = "/static/js/conceptualModel/images";
STENCIL_PATH = "/static/js/conceptualModel/stencils";
可以通过改变全局变量,控制各个组件的高宽。
EditorUi.prototype.menubarHeight = 0;
EditorUi.prototype.formatWidth = 300;
EditorUi.prototype.toolbarHeight = 0;
1. 添加tab栏
Sidebar.prototype.addTabsPalette = function (expand) {
var elt = document.createElement("ul");
elt.className = "mtTabs";
this.container.appendChild(elt);
var li1 = document.createElement("li");
var a1 = document.createElement("a");
li1.className = "active";
li1.addEventListener("click", function (e) {
var tabContents = document.getElementsByClassName("tabContent")[0].childNodes;
var className = this.className;
if (className.indexOf("active") < 0) {
var children = this.parentNode.childNodes;
for (var i = 0; i < children.length; i++) {
children[i].className = "";
}
this.className = "active";
tabContents[0].className = "tab-pane fade active";
tabContents[1].className = "tab-pane fade";
}
});
a1.innerText = "GeoIcons";
li1.appendChild(a1);
var li2 = document.createElement("li");
var a2 = document.createElement("a");
a2.innerText = "General";
li2.appendChild(a2);
li2.addEventListener("click", function (e) {
var tabContents = document.getElementsByClassName("tabContent")[0].childNodes;
var className = this.className;
if (className.indexOf("active") < 0) {
var children = this.parentNode.childNodes;
for (var i = 0; i < children.length; i++) {
children[i].className = "";
}
this.className = "active";
tabContents[1].className = "tab-pane fade active";
tabContents[0].className = "tab-pane fade";
}
});
elt.appendChild(li1);
elt.appendChild(li2);
this.palettes['tabs'] = elt;
};
Sidebar.prototype.addTabContent = function (expand) {
var elt = document.createElement("div");
elt.className = "tabContent";
this.container.appendChild(elt);
var panel1 = document.createElement("div");
panel1.className = "tab-pane fade active";
elt.appendChild(panel1);
var panel2 = document.createElement("div");
panel2.className = "tab-pane fade";
elt.appendChild(panel2);
this.palettes['tabContent'] = elt;
};
2. 添加自定义内容
Sidebar.prototype.addGeoIconPalette = function (expand) {
var that = this;
$.ajax({
url: "/conceptualModel/getAllGeoIcons",
type: "get",
success: function (result) {
var iconList = result;
var tabContents = that.palettes['tabContent'].childNodes;
var elt = document.createElement('div');
tabContents[0].appendChild(elt);
var div = document.createElement('div');
div.className = 'geSidebar';
div.id = 'geoIconContainer';
div.style.boxSizing = 'border-box';
div.style.overflow = 'hidden';
div.style.width = '100%';
div.style.padding = '8px';
div.style.paddingTop = '14px';
div.style.paddingBottom = '0px';
elt.appendChild(div);
for (var i = 0; i < iconList.length; i++) {
var name = iconList[i].name;
var iconId = iconList[i].geoId;
var a = that.createGeoIconTemplate('image;html=1;labelBackgroundColor=#ffffff;image=' + iconList[i].pathUrl,
that.defaultImageWidth, that.defaultImageHeight, "", name, name != null, null, null, iconId);
div.appendChild(a);
}
}
});
};
//自定义创建方法,跳过 addEntry() 这一步,提高加载效率(×),搜索效率
Sidebar.prototype.createGeoIconTemplate = function (style, width, height, value, title, showLabel, showTitle, allowCellsInserted, iconId) {
var cells = [new mxCell((value != null) ? value : '', new mxGeometry(0, 0, width, height), style)];
cells[0].vertex = true;
cells[0].geoId = iconId;
return this.createVertexTemplateFromCells(cells, width, height, title, showLabel, showTitle, allowCellsInserted);
};
//地理图标tab的搜索功能
Sidebar.prototype.searchEntries = function (searchTerms, count, page, success, error) {
// 拿着 searchTerms 去数据库里搜索
if (this.activeTerms == '' || this.activeTerms != searchTerms){
this.activeTerms = searchTerms;
$.ajax({
url:'/conceptualModel/getGeoIconsByKey',
data:{
searchTerms:searchTerms
},
success:(result)=> {
// 填充字典
for (var i=0; i< result.length; i++){
var name = result[i].name;
var iconId = result[i].geoId;
var tags = [this.activeTerms, name];
this.createVertexTemplateEntry('image;html=1;labelBackgroundColor=#ffffff;image=' + result[i].pathUrl,
this.defaultImageWidth, this.defaultImageHeight, "", name, name != null, null, tags.join(" "), iconId);
}
// 该方法的源码
...
}
});
} else if (this.activeTerms == searchTerms){
//该方法的源码
...
}
};
3. 添加折叠框
//GraphEditor自带函数
Sidebar.prototype.addPaletteFunctions = function (id, title, expanded, fns) {
this.addPalette(id, title, expanded, mxUtils.bind(this, function (content) {
for (var i = 0; i < fns.length; i++) {
content.appendChild(fns[i](content));
}
}));
};
Sidebar.prototype.addPalette = function (id, title, expanded, onInit) {
...
}
1. 入口在 refresh() 函数中
Format.prototype.refresh = function () {
...
if(graph.isSelectionEmpty()){
//未选中任何元素
}
else if(graph.isEditing()){
//正在编辑元素
}
else{
//选中要素时,再接着区分不同情景
if(graph.getSelectionCount() > 1){}
else if(cell.style == "group"){}
else if(cell.isEdge()){}
else if(ss.image || !cell.isEdge()){}
else{}
}
...
}
2. 添加自定义内容
this.panels.push(new GeoElementsPanel(this,ui,div));
...
GeoElementsPanel = function (format, editorUi, container) {
BaseFormatPanel.call(this, format, editorUi, container);
this.init();
};
mxUtils.extend(GeoElementsPanel, BaseFormatPanel);
GeoElementsPanel.prototype.init = function () {
this.container.appendChild(this.addGeneralElements(this.createPanel()));
this.container.appendChild(this.addGeoElementSelect(this.createPanel()));
};
1. GraphEditor的方式
2. 更简单直接的方式
//可以动态添加二级菜单,以及二级菜单对应的方法
var submenu1 = menu.addItem('关联到...', null, null);
menu.addItem('几何形状', null, function(){
relate2Shape();
}, submenu1);
var subProperty = menu.addItem('属性特征', null, null, submenu1);
for (let i = 0; i < GeoElements.properties.length; i++) {
menu.addItem(GeoElements.properties[i].type, null, function(){
relate2Property(GeoElements.properties[i].type);
}, subProperty);
}
前端
var relate2Shape = ()=> {
var ss = graph.getSelectionCell();
var xmlDoc = mxUtils.createXmlDocument();
var root = xmlDoc.createElement('output');
xmlDoc.appendChild(root);
var xmlCanvas = new mxXmlCanvas2D(root);
var scale=graph.getView().scale;
var stackLayout = new mxStackLayout(graph, true);
var border=stackLayout.border;
var bounds = graph.getGraphBounds();
//求选中图形的坐标,坐标原点在左上
var cells = graph.model.cells;
var x = ss.geometry.x;
var y = ss.geometry.y;
for(let i in cells){ // cells 类数组对象 没有长度属性 和 数组的方法
if (i > 1 && cells[i].parent.id == 1 && cells[i].edge != true) {
if (cells[i].geometry.x < x ) {
x = cells[i].geometry.x;
}
if (cells[i].geometry.y < y ) {
y = cells[i].geometry.y;
}
}
}
//整幅图与局部图的坐标差
var dX = x - ss.geometry.x;
var dY = y - ss.geometry.y;
xmlCanvas.translate(
Math.floor((border / scale - bounds.x + dX) / scale),
Math.floor((border / scale - bounds.y + dY) / scale),
);
xmlCanvas.scale(1);
var graphRoot = _.cloneDeep(graph.model.root); //lodash的方法
//剔除没有选中的要素
for (var i = 0;i<graphRoot.children[0].children.length;i++){
var cell = graphRoot.children[0].children[i];
if (cell != ss){
graphRoot.children[0].children.splice(i,1);
}
}
var imgExport = new mxImageExport();
imgExport.drawState(graph.getView().getState(graphRoot), xmlCanvas);
var w = ss.geometry.width;
var h = ss.geometry.height;
var xml = mxUtils.getXml(root);
$.ajax({
url: "/userImage/userDIY",
data: {
width: w,
height: h,
xml: xml,
type: "几何形状",
conceptName:GeoElements.name
},
type: "post",
async: true,
success: (userImage)=>{
graph.clearSelection();
$("#geoElementSelect").val("几何形状");
//js原生触发DOM事件
$("#geoElementSelect").trigger("change");
...
GeoElements.shapeInfo.relateImages.push(userImage);
}
})
};
后端
@RequestMapping(value = "/userDIY",method = RequestMethod.POST)
UserImage userDIY(@RequestParam("width") String width,@RequestParam("height") String height,
@RequestParam("xml") String xml,@RequestParam("type") String type,
@RequestParam("conceptName")String conceptName) throws Exception {
...
//将图片保存到本地
MxGraphUtils mxGraphUtils = new MxGraphUtils();
mxGraphUtils.exportImage((int)Double.parseDouble(width),(int)Double.parseDouble(height), xml, resourcePath+"/userImage/", name);
...
return userImage;
}
public void exportImage(int w, int h,String xml,String path,String name) throws Exception {
try {
logger.info(""+w+" "+h);
logger.info(xml);
logger.info(path);
logger.info(name);
long t0 = System.currentTimeMillis();
BufferedImage image = mxUtils.createBufferedImage(w, h, Color.WHITE);
logger.info("1");
// Creates handle and configures anti-aliasing
Graphics2D g2 = image.createGraphics();
mxUtils.setAntiAlias(g2, true, true);
long t1 = System.currentTimeMillis();
logger.info("2");
// Parses request into graphics canvas
mxGraphicsCanvas2D gc2 = new mxGraphicsCanvas2D(g2);
parseXmlSax(xml, gc2);
long t2 = System.currentTimeMillis();
logger.info("before mkdirs");
File file = new File(path);
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
logger.info("after mkdirs");
ImageIO.write(image, "png", new File(path + name));
long t3 = System.currentTimeMillis();
logger.info("saved");
}
catch (Exception e){
logger.error(e.getMessage());
logger.error(e.toString());
}
}