1、写在前面:关于双边框形状,在mxgraph中有双边框椭圆形(doubleEllipse),我的双边框长方形就是据此拓展的。
2、该形状的用途:这个图形也是很有必要的,它可用在BPMN中的事务子流程。
3、关键拓展代码:
extension.js
/**
* 新增表单样式doubleRectangle
*
**/
function mxDoubleRectangle(bounds, fill, stroke, strokewidth){
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = (strokewidth != null) ? strokewidth: 1;
}
mxDoubleRectangle.prototype = new mxShape();
mxDoubleRectangle.prototype.constructor = mxDoubleRectangle;
mxDoubleRectangle.prototype.createVml = function() {
this.node = document.createElement('v:group');
var name = (this.isRounded) ? 'v:roundrect': 'v:rect';
this.background = document.createElement(name);
this.configureVmlShape(this.background);
this.node.appendChild(this.background);
// this.label = this.background;
this.isShadow = false;
this.fill = null;
this.foreground = document.createElement(name);
this.configureVmlShape(this.foreground);
this.node.appendChild(this.foreground);
this.stroke = null;
this.configureVmlShape(this.node);
return this.node;
};
mxDoubleRectangle.prototype.createSvg = function() {
var g = this.createSvgGroup('rect');
this.foreground = document.createElementNS(mxConstants.NS_SVG, 'rect');
this.foreground.setAttribute('shape-rendering', 'optimizeSpeed');
this.foreground.setAttribute('fill', 'none');
g.appendChild(this.foreground);
return g;
};
mxDoubleRectangle.prototype.redrawSvg = function(node) {
if (this.innerNode != null) {
this.updateSvgShape(this.innerNode);
if (this.shadowNode != null) {
this.updateSvgShape(this.shadowNode);
}
} else {
this.updateSvgShape(this.node);
}
this.updateSvgGlassPane();
this.updateSvgNode(this.foreground, 8);
};
mxDoubleRectangle.prototype.redrawVml = function() {
this.node.style.visibility = 'hidden';
this.updateVmlShape(this.node);
this.updateVmlGlassPane();
this.node.style.visibility = 'hidden';
this.background.style.visibility = 'hidden';
this.updateVmlShape(this.background);
this.updateVmlGlassPane();
this.background.style.visibility = 'visible';
this.foreground.style.visibility = 'hidden';
this.updateVmlShape(this.foreground);
this.updateVmlGlassPane();
this.foreground.style.visibility = 'visible';
var inset = 8;
var w = Math.floor(this.bounds.width);
var h = Math.floor(this.bounds.height);
var x = Math.floor(this.bounds.x);
var y = Math.floor(this.bounds.y);
this.background.style.top = inset/2 + 'px';
this.background.style.left = inset/2 + 'px';
this.background.style.width = Math.max(0, w - inset) + 'px';
this.background.style.height = Math.max(0, h - inset) + 'px';
};
mxDoubleRectangle.prototype.updateSvgNode = function(node, inset) {
inset = (inset != null) ? inset: 0;
if (node != null) {
var strokeWidth = Math.max(1, this.strokewidth * this.scale);
if (this.crisp) {
node.setAttribute('shape-rendering', 'crispEdges');
} else {
node.removeAttribute('shape-rendering');
}
if (this.style != null && this.style[mxConstants.STYLE_SMOOTH]) {
var pts = this.points;
var n = pts.length;
if (n > 3) {
var points = 'M ' + pts[0].x + ' ' + pts[0].y + ' ';
points += ' Q ' + pts[1].x + ' ' + pts[1].y + ' ' + ' ' + pts[2].x + ' ' + pts[2].y;
for (var i = 3; i < n; i++) {
points += ' T ' + pts[i].x + ' ' + pts[i].y;
}
node.setAttribute('d', points);
}
}
if (this.isDashed) {
var phase = Math.max(1, Math.floor(3 * this.scale));
node.setAttribute('stroke-dasharray', phase + ',' + phase);
}
if (this.isRounded) {
var w = this.bounds.width-inset;
var h = this.bounds.height-inset;
var r = Math.min(w * mxConstants.RECTANGLE_ROUNDING_FACTOR, h * mxConstants.RECTANGLE_ROUNDING_FACTOR);
node.setAttribute('rx', r);
node.setAttribute('ry', r);
}
node.setAttribute('stroke',this.stroke);
node.setAttribute('stroke-width', strokeWidth);
node.setAttribute('x', this.bounds.x +inset/2);
node.setAttribute('y', this.bounds.y +inset/2);
node.setAttribute('width', Math.max(0, this.bounds.width - inset));
node.setAttribute('height', Math.max(0, this.bounds.height - inset));
}
};
mxDoubleRectangle.prototype.configureVmlShape = function(node) {
node.style.position = 'absolute';
var color = this.stroke;
if (color != null && color != mxConstants.NONE) {
node.setAttribute('stroked', 'true');
node.setAttribute('strokecolor', color);
} else {
node.setAttribute('stroked', 'false');
}
color = this.fill;
node.style.background = '';
if (color != null && color != mxConstants.NONE) {
if (this.fillNode == null) {
this.fillNode = document.createElement('v:fill');
node.appendChild(this.fillNode);
}
this.updateVmlFill(this.fillNode, color, this.gradient, this.gradientDirection, this.opacity);
} else {
node.setAttribute('filled', 'false');
if (this.points == null) {
this.configureTransparentBackground(node);
}
}
if ((this.isDashed || this.opacity != null) && this.strokeNode == null) {
this.strokeNode = document.createElement('v:stroke');
node.appendChild(this.strokeNode);
}
if (this.strokeNode != null) {
if (this.strokeNode != null) {
if (this.isDashed) {
var phase = Math.max(1, Math.floor(3 * this.scale));
var pat = phase + ' ' + phase;
if (this.strokeNode.getAttribute('dashstyle') != pat) {
this.strokeNode.setAttribute('dashstyle', pat);
}
} else if (this.strokeNode.getAttribute('dashstyle') != 'solid') {
this.strokeNode.setAttribute('dashstyle', 'solid');
}
}
if (this.opacity != null) {
this.strokeNode.setAttribute('opacity', this.opacity + '%');
}
}
if (this.isShadow && this.fill != null) {
if (this.shadowNode == null) {
this.shadowNode = document.createElement('v:shadow');
this.shadowNode.setAttribute('on', 'true');
this.shadowNode.setAttribute('color', mxConstants.SHADOWCOLOR);
node.appendChild(this.shadowNode);
}
}
if (node.nodeName == 'roundrect') {
try {
node.setAttribute('arcsize', String(mxConstants.RECTANGLE_ROUNDING_FACTOR * 100) + '%');
} catch(e) {}
}
this.strokeNode = null;
};
/**
*拓展该形状输出img的绘制方法
**/
mxImageExport.prototype.initShapes = function() {
this.shapes = [];
//其他形状的绘制也在此定义,就是源码中的,在此只写了新增的代码
this.shapes['doubleRectangle'] = {
drawShape: function(canvas, state, bounds, background) {
if (background) {
if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false)) {
var size = Math.max(bounds.width / 10, bounds.height / 10);
canvas.roundrect(bounds.x, bounds.y, bounds.width, bounds.height, size, size);
} else {
canvas.rect(bounds.x, bounds.y, bounds.width, bounds.height);
}
return true;
} else {
canvas.fillAndStroke();
var inset = 8;
var x = bounds.x;
var y = bounds.y;
var w = bounds.width;
var h = bounds.height;
x += inset/2;
y += inset/2;
w -= inset;
h -= inset;
if (w > 0 && h > 0) {
if (mxUtils.getValue(state.style, mxConstants.STYLE_ROUNDED, false)) {
var size = Math.max(w / 10, h / 10);
canvas.rect(x, y, w,h,size,size);
}else {
canvas.rect(x,y,w,h);
}
}
canvas.stroke();
}
}
};
};
4、应用方法:
应用新的样式时可以在default-style.xml中写该样式:
<add as="transaction" >
<add as="shape" value="doubleRectangle"/>
<add as="strokeColor" value="black"/>
<add as="fillColor" value="#F2F2F2"/>
<add as="gradientColor" value="#F2F2F2"/>
<add as="verticalAlign" value="top"/>
<add as="rounded" value="0"/>
</add>
这就是BPMN中事务子流程的样式定义。
然后,在graph的js中:
graph.cellRenderer.registerShape('doubleRectangle', mxDoubleRectangle);
var style = graph.getStylesheet().getDefaultVertexStyle();
style[mxConstants.STYLE_SHAPE] = 'doubleRectangle';
这样就可以用这个样式啦啦~~
*************************格叽格叽**************************
终于写完了 lysh miss wanan~