这两天,又扩展了一下基于excanvas和jquery的拓扑功能。下来,准备增加画图工具了。
/** * @author leishu <[email protected]> */ var jvConstants = { ELEMENT_ID_PREFIX : 'jvElement_', ELEMENT_ID_COUNT : 0, DEFAULT_VALID_COLOR:'#00FF00', DEFAULT_INVALID_COLOR:'#FF0000', HIGHLIGHT_STROKEWIDTH:3, CURSOR_MOVABLE_ELEMENT:'move', CURSOR_MOVABLE_EDGE:'move', CURSOR_CONNECT:'pointer', VALID_COLOR:'#00FF00', INVALID_COLOR:'#FF0000', STYLE_STROKECOLOR:'strokeColor', STYLE_STROKEWIDTH:'strokeWidth', SHAPE_RECTANGLE:'rectangle', SHAPE_ELLIPSE:'ellipse', SHAPE_TEXT:'text', ELEMENT_GROUP:'group', ELEMENT_TYPE_EDGE:'edge', BACKGROUND_COLOR:'background-color', ACTION_MOUSEDOWN:'mousedown', ACTION_MOUSEUP:'mouseup', ACTION_MOVE : 'mousemove', STYLE_ALIGN:'align', STYLE_SPACING:'spacing', STYLE_SPACING_TOP:'spacingTop', STYLE_SPACING_LEFT:'spacingLeft', STYLE_SPACING_BOTTOM:'spacingBottom', STYLE_SPACING_RIGHT:'spacingRight', STYLE_HORIZONTAL:'horizontal', STYLE_FONTCOLOR:'color', STYLE_FONTFAMILY:'font-family', STYLE_FONTSIZE:'font-size', STYLE_OVERFLOW:'overflow', ALIGN_CENTER:'center', DEFAULT_FONTFAMILY:'Arial,Helvetica', DEFAULT_FONTSIZE:10, SELECT_START : 'start', SELECT_END : 'end', LABEL_LOCATION_MIDDLE : 'middle', LABEL_LOCATION_BOTTOM : 'bottom', LABEL_INTERVAL : 3, END_POINT_LEFTTOP : 'lt', END_POINT_LEFTMIDDLE : 'lm', END_POINT_LEFTBOTTOM : 'lb', END_POINT_MIDDLETOP : 'mt', END_POINT_MIDDLEBOTTOM : 'mb', END_POINT_RIGHTTOP : 'rt', END_POINT_RIGHTMIDDLE : 'rm', END_POINT_RIGHTBOTTOM : 'rb' }; function getMouseButton(eventObject) { var buttons = { 'left':false, 'middle':false, 'right':false }; if(eventObject.toString && eventObject.toString().indexOf('MouseEvent') != -1) { switch(eventObject.button) { case 0: buttons.left = true; break; case 1: buttons.middle = true; break; case 2: buttons.right = true; break; default: break; } } else if(eventObject.button) { switch(eventObject.button) { case 1: buttons.left = true; break; case 2: buttons.right = true; break; case 3: buttons.left = true; buttons.right = true; break; case 4: buttons.middle = true; break; case 5: buttons.left = true; buttons.middle = true; break; case 6: buttons.middle = true; buttons.right = true; break; case 7: buttons.left = true; buttons.middle = true; buttons.right = true; break; default: break; } } else { return false; } return buttons; }; function jvMap(){ this.data = new Array(); }; jvMap.prototype.clear=function(){ this.data = []; }; jvMap.prototype.get=function(key){ $(this.data).each( function(i) { if (this.key === k){ return this.value; } }); return null; }; jvMap.prototype.put=function(k, v){ $(this.data).each( function(i) { if (this.key === k){ this.value = v; return; } }); this.data.push({key:k, value:v}); }; jvMap.prototype.remove=function(k){ var d = []; $(this.data).each( function(i) { if (this.key != k){ d.push({key:this.key,value:this.value}); } }); this.data = d; }; jvMap.prototype.isEmpty = function() { if (this.data.length == 0){ return true; }else{ return false; } }; jvMap.prototype.size = function() { return this.data.length; }; jvMap.prototype.containsKey=function(k){ $(this.data).each( function(i) { if (this.key === k){ return true; } }); return false; }; jvMap.prototype.getValues=function(){ var result=[]; $(this.data).each( function(i) { result.push(this.value); }); return result; }; function jvPoint(x,y){ this.x = (x!=null)?x:0; this.y = (y!=null)?y:0; }; jvPoint.prototype.x=null; jvPoint.prototype.y=null; jvPoint.prototype.equals=function(obj){ return obj.x==this.x&&obj.y==this.y; }; function jvEndPoint(x, y, type, cursor){ jvPoint.call(this, x, y); this.type = type; this.cursor = cursor; }; jvEndPoint.prototype=new jvPoint(); jvEndPoint.prototype.constructor=jvEndPoint; function jvRectangle(x, y, width, height){ jvPoint.call(this, x, y); this.width = (width != null) ? width : 0; this.height = (height != null) ? height : 0; }; jvRectangle.prototype=new jvPoint(); jvRectangle.prototype.constructor=jvRectangle; jvRectangle.prototype.width=null; jvRectangle.prototype.height=null; jvRectangle.prototype.getCenterX=function(){ return this.x+this.width/2; }; jvRectangle.prototype.getCenterY=function(){ return this.y+this.height/2; }; jvRectangle.prototype.getPoint=function(){ return new jvPoint(this.x,this.y); }; jvRectangle.prototype.equals=function(obj){ return obj.x==this.x&&obj.y==this.y&&obj.width==this.width&&obj.height==this.height; }; jvRectangle.prototype.grow=function(amount){ this.x-=amount; this.y-=amount; this.width+=2*amount; this.height+=2*amount; }; function jvStylesheet(){ this.styles = []; this.putDefaultElementStyle(this.createDefaultElementStyle()); this.putDefaultEdgeStyle(this.createDefaultEdgeStyle()); this.putDefaultTextStyle(this.createDefaultTextStyle()); return this; }; jvStylesheet.prototype.createDefaultElementStyle = function(){ var style=new Object(); style[jvConstants.STYLE_SHAPE]=jvConstants.SHAPE_RECTANGLE; style[jvConstants.STYLE_FILLCOLOR]='#C3D9FF'; style[jvConstants.STYLE_STROKECOLOR]='#6482B9'; style[jvConstants.STYLE_FONTCOLOR]='#774400'; style[jvConstants.STYLE_STROKEWIDTH] = 2; return style; }; jvStylesheet.prototype.createDefaultEdgeStyle = function(){ var style=new Object(); style[jvConstants.STYLE_SHAPE]=jvConstants.SHAPE_CONNECTOR; style[jvConstants.STYLE_STROKECOLOR]='#6482B9'; style[jvConstants.STYLE_FONTCOLOR]='#446299'; style[jvConstants.STYLE_STROKEWIDTH] = 2; return style; }; jvStylesheet.prototype.createDefaultTextStyle = function(){ var style=new Object(); style[jvConstants.STYLE_ALIGN] = jvConstants.ALIGN_CENTER; style[jvConstants.STYLE_FONTCOLOR] = 'gray'; style[jvConstants.STYLE_FONTFAMILY] = jvConstants.DEFAULT_FONTFAMILY; style[jvConstants.STYLE_FONTSIZE] = jvConstants.DEFAULT_FONTSIZE; style[jvConstants.STYLE_SPACING] = 0; style[jvConstants.STYLE_SPACING_TOP] = 0; style[jvConstants.STYLE_SPACING_RIGHT] = 0; style[jvConstants.STYLE_SPACING_BOTTOM] = 0; style[jvConstants.STYLE_SPACING_LEFT] = 0; style[jvConstants.STYLE_OVERFLOW] = 'visible'; style['z-index'] = 2; return style; }; jvStylesheet.prototype.putDefaultElementStyle=function(style){ this.putCellStyle('defaultElement',style); }; jvStylesheet.prototype.putDefaultEdgeStyle=function(style){ this.putCellStyle('defaultEdge',style); }; jvStylesheet.prototype.putDefaultTextStyle=function(style){ this.putCellStyle('defaultText',style); }; jvStylesheet.prototype.getDefaultElementStyle=function(){ return this.styles['defaultElement']; }; jvStylesheet.prototype.getDefaultEdgeStyle=function(){ return this.styles['defaultEdge']; }; jvStylesheet.prototype.getDefaultTextStyle=function(){ return this.styles['defaultText']; }; jvStylesheet.prototype.putCellStyle=function(name,style){ this.styles[name] = style; }; function jvState(x, y, width, height, action){ jvRectangle.call(this, x, y, width, height); this.action = action; } jvState.prototype =new jvRectangle(); jvState.prototype.constructor = jvState; jvState.prototype.startX = null; jvState.prototype.startY = null; jvState.prototype.elementID = null; jvState.prototype.changed = false; jvState.prototype.resized = false; jvState.prototype.position=function(x, y, width, height){ jvRectangle.call(this, x, y, width, height); }; function jvElement(canvas, type, x, y, width, height, label){ jvRectangle.call(this, x, y, width, height); this.canvas = canvas; this.type = type; this.label = label; }; jvElement.prototype =new jvRectangle(); jvElement.prototype.constructor = jvElement; jvElement.prototype.id = null; jvElement.prototype.shape = null; jvElement.prototype.frame = null; jvElement.prototype.endPoints = null; jvElement.prototype.source = null; jvElement.prototype.target = null; jvElement.prototype.edges = null; jvElement.prototype.edge=false; jvElement.prototype.state=null; jvElement.prototype.edge=false; jvElement.prototype.areaCoords = []; jvElement.prototype.area = null; jvElement.prototype.text = null; jvElement.prototype.isEdge=function(){ return this.edge; }; jvElement.prototype.setStyle = function(style){ jQuery.extend(this.style, style); this.reDraw(); this.unselect(); }; jvElement.prototype.setLabelLocation = function(location){ if (this.text){ this.text.location = location; this.text.setY(); $(this.text.table).css({top:this.text.y}); } }; jvElement.prototype.create = function(){ this.id = $.jvChart.getElementID(); this.container = this.canvas.parentElement; if (this.type == jvConstants.ELEMENT_TYPE_EDGE){ this.style = $.jvChart.getStylesheet().getDefaultEdgeStyle(); this.edge = true; }else{ this.edges = []; this.style = $.jvChart.getStylesheet().getDefaultElementStyle(); this.style[jvConstants.BACKGROUND_COLOR] = $(this.container).css(jvConstants.BACKGROUND_COLOR); } if (this.label){ this.text = new jvTextElement(this.canvas, this.label, this); } this.draw(); this.createArea(); this.bindMouseEvents(); }; jvElement.prototype.move = function(e){ if (this.height < 0){ var t = this.y + this.height; this.y += this.height; this.height = Math.abs(this.height); this.state.y = this.y; this.state.height = this.height; this.state.startY = e.clientY; if (this.state.action == jvConstants.END_POINT_MIDDLEBOTTOM){ this.state.action = jvConstants.END_POINT_MIDDLETOP; }else if (this.state.action == jvConstants.END_POINT_MIDDLETOP){ this.state.action = jvConstants.END_POINT_MIDDLEBOTTOM; } } this.state.changed = true; this.updateFrame(); }; jvElement.prototype.updateFrame = function(){ $(this.frame).css('left', this.x).css('top', this.y) .css('width', this.width).css('height', this.height); }; jvElement.prototype.updateEndPoints = function(){ var c = this.container; if (this.endPoints){ $(this.endPoints).remove(); this.endPoints = null; } if (this.isEdge()){ }else{ var xr = this.x + this.width, xm = Math.round(this.x + this.width /2), yr = this.y + this.height, ym = Math.round(this.y + this.height /2); var e = []; e.push(new jvEndPoint(this.x, this.y, jvConstants.END_POINT_LEFTTOP, 'nw-resize')); e.push(new jvEndPoint(xm, this.y, jvConstants.END_POINT_MIDDLETOP, 'row-resize')); e.push(new jvEndPoint(xr, this.y, jvConstants.END_POINT_RIGHTTOP, 'ne-resize')); e.push(new jvEndPoint(this.x, ym, jvConstants.END_POINT_LEFTMIDDLE, 'col-resize')); e.push(new jvEndPoint(xr, ym, jvConstants.END_POINT_RIGHTMIDDLE, 'col-resize')); e.push(new jvEndPoint(this.x, yr, jvConstants.END_POINT_LEFTBOTTOM, 'sw-resize')); e.push(new jvEndPoint(xm, yr, jvConstants.END_POINT_MIDDLEBOTTOM, 'row-resize')); e.push(new jvEndPoint(xr, yr, jvConstants.END_POINT_RIGHTBOTTOM, 'se-resize')); var ep = this.endPoints = []; $(e).each(function(i){ var l = this.x - 3; var t = this.y - 3; ep.push($.jvChart.createElement('div', { action:this.type}, {position: 'absolute', 'z-index':1, 'background-color':'lime', left:l, top:t, width: '7px', height: '7px', overflow:'hidden', cursor:this.cursor}, c)); }); var $e = this; $(ep).each(function(i){ $(this).mousedown(function (e) { $e.refreshState(e, $(this).attr('action')); return false; }).mouseup(function (e) { return $e.mouseup($(this).attr('action')); }); }); } }; jvElement.prototype.reDraw = function(x, y){ if (this.shape){ $(this.shape).remove(); } this.x += x || 0; this.y += y || 0; this.draw(); this.updateFrame(); this.updateEndPoints(); this.bindMouseEvents(); if (this.text && this.state){ var xc = x || this.x - this.state.x; var yc = y || this.y - this.state.y; this.text.refreshPosition(xc, yc); } if (!this.isEdge && !this.selected){ this.clearState(); }else if (this.state){ this.state.changed = false; } if (!this.isEdge()){ $(this.edges).each(function(i){ this.reDraw(); }); } }; jvElement.prototype.createArea = function(){ }; jvElement.prototype.createFrame = function(){ if (this.frame != null){return;} var c = this.container; var color = 'lime'; if (this.type == jvConstants.ELEMENT_GROUP){ color = 'slategray'; } this.frame = $.jvChart.createElement('div', { id: c.id + '-frame' }, {position: 'absolute', 'z-index':-1, border:'dotted 2 ' + color, left:this.x, top:this.y, width: this.width, height: this.height}, c); $(this.frame).mouseup(function (e) { return true; }); if (this.type != jvConstants.ELEMENT_GROUP){ this.updateEndPoints(); } }; jvElement.prototype.removeFrame = function(){ $(this.frame).remove(); this.frame = null; $(this.endPoints).remove(); this.endPoints = null; this.clearState(); }; jvElement.prototype.buildArea = function(){ var str = "<area shape=poly style='cursor:move; ' coords="; var length = $(this.areaCoords).length; $(this.areaCoords).each(function(i){ str += this.x + ',' + this.y; if (i != length - 1){ str += ','; } }); str +='>'; var area = document.createElement(str); this.container.imagemap.appendChild(area); this.area = area; }; jvElement.prototype.setShape = function(n){ this.shape = []; if ($.browser.msie) { var shapes = this.canvas.getElementsByTagName("shape"); for (var i = n; i > 0; i--){ this.shape.push(shapes[shapes.length - i]); } } }; jvElement.prototype.selected = false; jvElement.prototype.toggle = function(e, action){ if (this.selected){ this.unselect(); }else{ this.select(e, action); } }; jvElement.prototype.select = function(e, action){ if (e.ctrlKey){ }else{ var $e = this; var data = this.container.selected.getValues(); $(data).each(function(i){ if($e.id != this.id){ this.unselect(); } }); } if (!this.selected){ this.createFrame(); this.selected = true; this.container.selected.addElement(this); } this.refreshState(e, action); document.onselectstart=new Function ("return false"); return false; }; jvElement.prototype.refreshState = function(e, action){ if (this.state){ this.state.position(this.x, this.y, this.width, this.height); this.state.action = action; }else{ this.state = new jvState(this.x, this.y, this.width, this.height, action); this.state.elementID = this.id; } this.state.startX = e.clientX; this.state.startY = e.clientY; }; jvElement.prototype.unselect = function(){ this.container.selected.deleteElement(this); this.selected = false; this.removeFrame(); this.clearState(); return false; }; jvElement.prototype.clearState = function(){ this.state = null; }; jvElement.prototype.mouseup = function(action){ if (this.state && !this.state.changed){ this.state.action = action; return false; } return true; }; jvElement.prototype.bindMouseEvents = function(){ if (this.idEdge){return;} var $e = this; $(this.shape).css({cursor:'move'}).mousedown(function (e) { if (e.ctrlKey){ if (!$e.selected){ $e.select(e, jvConstants.ACTION_MOVE); $e.selected = jvConstants.SELECT_START; } }else{ if (!$e.selected){ $e.select(e, jvConstants.ACTION_MOVE); }else { $e.refreshState(e, jvConstants.ACTION_MOVE); } } var group = $e.container.selected; if (group.size() > 1){ group.refreshState(e, jvConstants.ACTION_MOVE); } return false; }).mouseup(function (e) { if (e.ctrlKey){ if ($e.selected == jvConstants.SELECT_END){ $e.unselect(); }else{ $e.selected = jvConstants.SELECT_END; } }else{ var group = $e.container.selected; if (group.size() > 1){ return group.mouseup(jvConstants.ACTION_MOVE); } if ($e.state){ return $e.mouseup(jvConstants.ACTION_MOVE); } } return false; }); }; function jvGroup(canvas){ jvElement.call(this, canvas, jvConstants.ELEMENT_GROUP); this.id = $.jvChart.getElementID(); this.container = this.canvas.parentElement; return this; }; jvGroup.prototype = new jvElement(); jvGroup.prototype.constructor = jvGroup; jvGroup.prototype.action = null; jvGroup.prototype.elements = new jvMap(); jvGroup.prototype.addElement = function(element){ this.elements.put(element.id, element); this.refreshFrame(); }; jvGroup.prototype.deleteElement = function(element){ this.elements.remove(element.id); this.refreshFrame(); }; jvGroup.prototype.getValues = function(){ return this.elements.getValues(); }; jvGroup.prototype.size = function(){ return this.elements.size(); }; jvGroup.prototype.containsKey=function(k){ return this.elements.containsKey(k); }; jvGroup.prototype.refreshFrame = function(){ var $g = this; var elements = this.getValues(); if (this.size() < 2){ this.removeFrame(); return; } $g.x = elements[0].x; $g.y = elements[0].y; $g.width = elements[0].width; $g.height = elements[0].height; $(elements).each(function(i){ $g.x = Math.min($g.x, this.x); $g.y = Math.min($g.y, this.y); }); $(elements).each(function(i){ $g.width = Math.max($g.width, this.x + this.width - $g.x); $g.height = Math.max($g.height, this.y + this.height - $g.y); }); this.createFrame(); }; jvGroup.prototype.reDraw = function(){ var x = this.x - this.state.x; var y = this.y - this.state.y; $(this.getValues()).each(function(i){ this.reDraw(x, y); }); }; function jvEllipseElement(canvas, x, y, width, height, label){ jvElement.call(this, canvas, jvConstants.SHAPE_ELLIPSE, x, y, width, height, label); this.create(); return this; }; jvEllipseElement.prototype = new jvElement(); jvEllipseElement.prototype.constructor = jvEllipseElement; jvEllipseElement.prototype.draw = function(){ var ctx = this.canvas.getContext('2d'); ctx.beginPath(); var hB = (this.width / 2) * .5522848, vB = (this.height / 2) * .5522848, eX = this.x + this.width, eY = this.y + this.height, mX = this.x + this.width / 2, mY = this.y + this.height / 2; ctx.moveTo(this.x, mY); ctx.bezierCurveTo(this.x, mY - vB, mX - hB, this.y, mX, this.y); ctx.bezierCurveTo(mX + hB, this.y, eX, mY - vB, eX, mY); ctx.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY); ctx.bezierCurveTo(mX - hB, eY, this.x, mY + vB, this.x, mY); ctx.closePath(); ctx.strokeStyle = this.style[jvConstants.STYLE_STROKECOLOR]; ctx.lineWidth = this.style[jvConstants.STYLE_STROKEWIDTH]; ctx.fillStyle = this.style[jvConstants.BACKGROUND_COLOR]; ctx.fill(); ctx.stroke(); this.setShape(2); }; jvEllipseElement.prototype.createArea = function(){ if (!this.imagemap){return;} if (this.area){ $(this.area).remove(); this.areaCoords = []; } var a = 0.5 * Math.sqrt(this.height * this.height + this.width * this.width), b = 0.5 * this.height, e = Math.sqrt(1.0 - b * b / a / a), ox = 0.5 * (this.x + this.width), oy = 0.5 * (this.y + this.height), phi = 0, sinphi = Math.sin(phi), cosphi = Math.cos(phi); for (var i=0;i< 360; i+=15){ var sita = Math.PI / 180.0 * i , cn = Math.cos(sita), sn = Math.sin(sita), r = b / Math.sqrt( 1.0 - e * e * cn * cn), tx = r * cn , ty = r * sn, xx = tx * cosphi - ty * sinphi, yy = ty * cosphi + tx * sinphi; this.areaCoords.push(new jvPoint(Math.round(xx + ox), Math.round(yy + oy))); } this.buildArea(); }; function jvRectangleElement(canvas, x, y, width, height, radius, label){ jvElement.call(this, canvas, jvConstants.SHAPE_RECTANGLE, x, y, width, height, label); this.radius = radius; this.create(); return this; }; jvRectangleElement.prototype = new jvElement(); jvRectangleElement.prototype.constructor = jvRectangleElement; jvRectangleElement.prototype.draw = function(){ var ctx = this.canvas.getContext('2d'); ctx.beginPath(); if (!this.radius) { ctx.rect(this.x, this.y, this.width, this.height); } else { ctx.moveTo(this.x, this.y + this.radius); ctx.lineTo(this.x, this.y + this.height - this.radius); ctx.quadraticCurveTo(this.x, this.y + this.height, this.x + this.radius, this.y + this.height); ctx.lineTo(this.x + this.width - this.radius, this.y + this.height); ctx.quadraticCurveTo(this.x + this.width, this.y + this.height, this.x + this.width, this.y + this.height - this.radius); ctx.lineTo(this.x + this.width, this.y + this.radius); ctx.quadraticCurveTo(this.x + this.width, this.y , this.x + this.width - this.radius, this.y); ctx.lineTo(this.x + this.radius, this.y); ctx.quadraticCurveTo(this.x , this.y, this.x, this.y + this.radius); } ctx.closePath(); ctx.strokeStyle = this.style[jvConstants.STYLE_STROKECOLOR]; ctx.lineWidth = this.style[jvConstants.STYLE_STROKEWIDTH]; ctx.fillStyle = this.style[jvConstants.BACKGROUND_COLOR]; ctx.fill(); ctx.stroke(); this.setShape(2); }; function jvEdgeElement(canvas, source, target){ jvElement.call(this, canvas, jvConstants.ELEMENT_TYPE_EDGE); this.source = source; this.target = target; this.edge = true; this.create(); return this; }; jvEdgeElement.prototype = new jvElement(); jvEdgeElement.prototype.constructor = jvEdgeElement; jvEdgeElement.prototype.draw = function(){ var ctx = this.canvas.getContext('2d'); var p = [{x: this.source.x + this.source.width / 2, y: this.source.y - 1}, {x: this.source.x + this.source.width / 2, y: this.source.y + this.source.height + 1}, {x: this.source.x - 1, y: this.source.y + this.source.height / 2}, {x: this.source.x + this.source.width + 1, y: this.source.y + this.source.height / 2}, {x: this.target.x + this.target.width / 2, y: this.target.y - 1}, {x: this.target.x + this.target.width / 2, y: this.target.y + this.target.height + 1}, {x: this.target.x - 1, y: this.target.y + this.target.height / 2}, {x: this.target.x + this.target.width + 1, y: this.target.y + this.target.height / 2}]; var d = {}, dis = []; for (var i = 0; i < 4; i++) { for (var j = 4; j < 8; j++) { var dx = Math.abs(p[i].x - p[j].x), dy = Math.abs(p[i].y - p[j].y); if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) { dis.push(dx + dy); d[dis[dis.length - 1]] = [i, j]; } } } if (dis.length == 0) { var res = [0, 4]; } else { var res = d[Math.min.apply(Math, dis)]; } var x1 = p[res[0]].x, y1 = p[res[0]].y, x4 = p[res[1]].x, y4 = p[res[1]].y/*, dx = Math.max(Math.abs(x1 - x4) / 2, 10), dy = Math.max(Math.abs(y1 - y4) / 2, 10), x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3), y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3), x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3), y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3)*/; this.x = x1; this.y = y1; this.width = x4; this.height = y4; ctx.beginPath(); ctx.strokeStyle = this.style[jvConstants.STYLE_STROKECOLOR]; ctx.lineWidth = this.style[jvConstants.STYLE_STROKEWIDTH]; ctx.moveTo(x1, y1); ctx.lineTo(x4, y4); ctx.closePath(); ctx.stroke(); this.setShape(1); }; function jvTextElement(canvas, value, parent){ jvElement.call(this, canvas, jvConstants.SHAPE_TEXT); this.value = value; this.location = jvConstants.LABEL_LOCATION_BOTTOM; if (parent){ this.parent = parent; this.create(); } return this; }; jvTextElement.prototype = new jvElement(); jvTextElement.prototype.constructor = jvTextElement; jvTextElement.prototype.parent = null; jvTextElement.prototype.value = null; jvTextElement.prototype.table = null; jvTextElement.prototype.location = null; jvTextElement.prototype.position = function(){ this.height = this.table.offsetHeight; this.setY(); this.width = this.table.offsetWidth; this.setX(); $(this.table).css({left:this.x, top:this.y, width:this.width, height:this.height}); }; jvTextElement.prototype.setX = function(){ this.x = this.parent.x + (this.parent.width - this.width) / 2; }; jvTextElement.prototype.setY = function(){ if (this.location == jvConstants.LABEL_LOCATION_MIDDLE){ this.y = this.parent.y + (this.parent.height - this.height) / 2; }else{ this.y = this.parent.y + this.parent.height + jvConstants.LABEL_INTERVAL; } }; jvTextElement.prototype.refreshX = function(x){ if (this.parent.state.resized){ this.setX(); }else{ this.x += x || 0; } }; jvTextElement.prototype.refreshY = function(y){ if (this.parent.state.resized){ this.setY(); }else{ this.y += y || 0; } }; jvTextElement.prototype.refreshPosition = function(x, y){ this.refreshX(x); this.refreshY(y); $(this.table).css({left:this.x, top:this.y}); }; jvTextElement.prototype.create = function(){ this.createHtmlTable(); this.canvas.appendChild(this.table); this.position(); }; jvTextElement.prototype.createHtmlTable=function(){ this.table=document.createElement('table'); $(this.table).css({position:'absolute', 'border-collapse':'collapse'}); var style = $.jvChart.getStylesheet().getDefaultTextStyle(); $(this.table).css(style); var tbody=document.createElement('tbody'); var tr=document.createElement('tr'); var td=document.createElement('td'); tr.appendChild(td); if (this.value){ $(td).html(this.value); } tbody.appendChild(tr); this.table.appendChild(tbody); }; $.jvChart = $.jvChart || {}; $.extend($.jvChart,{ createElement : function(tag, attribs, styles, parent, nopad) { var el = document.createElement(tag); if (attribs) $(el).attr(attribs); if (nopad) $(el).css({padding: 0, border: 'none', margin: 0}); if (styles) $(el).css(styles); if (parent) $(parent).append(el); return el; }, createCanvas : function(div){ var cvs = $.jvChart.createElement('canvas', { id: div.id + '-canvas', width: $(div).width(), height: $(div).height() }, {position: 'absolute'}, div); if ($.browser.msie) { G_vmlCanvasManager.initElement(cvs); cvs = document.getElementById(cvs.id); } return cvs; }, createSelect : function(div){ var sd = $.jvChart.createElement('div', { id: div.id + '-select', left : 0, top : 0, width: 1, height: 1 }, {position: 'absolute'}, div); return sd; }, getElementID : function(){ return jvConstants.ELEMENT_ID_PREFIX + jvConstants.ELEMENT_ID_COUNT ++; }, dragMove: function(div, e) { var element = div.selected; if (div.selected.size() == 1){ var element = div.selected.getValues()[0]; } var x = e.clientX - element.state.startX; var y = e.clientY - element.state.startY; element.x = element.state.x + x; element.y = element.state.y + y; element.move(e); }, bottomResize : function(div, e) { $(div.selected.getValues()).each( function(i) { var y = e.clientY - this.state.startY; this.height = this.state.height + y; this.state.changed = true; this.state.resized = true; this.move(e); }); }, topResize : function(div, e) { $(div.selected.getValues()).each( function(i) { var y = e.clientY - this.state.startY; this.y = this.state.y + y; this.height = this.state.height - y; this.state.changed = true; this.state.resized = true; this.move(e); }); }, reDrawConnections : function (paper){ paper.edgePaper.ctx.clearRect(0, 0, paper.width, paper.height); $(paper.edgePaper.edges).each(function(i){ $.jvChart.drawConnection(paper.edgePaper, document.getElementById(paper.edgePaper.edges[i][0]), document.getElementById(paper.edgePaper.edges[i][1]), 'rgb(0,0,0)', 2); }); }, reDrawElements : function (paper){ $('.ui-draggable', $(paper.canvas)).remove(); $(paper.elements).each(function(i){ var e = paper.elements[i]; if (e.type == 'ellipse'){ $.jvChart.drawEllipse(paper, e.id, e.x, e.y, e.rx, e.ry, e.color, e.width); }else if(e.type == 'rectangle'){ $.jvChart.drawRect(paper, e.id, e.x, e.y, e.w, e.h, e.r, e.color, e.width); } }); } }); (function($) { $.fn.jvChart = function() { $.extend($.jvChart,{getCvsId : function(){ return getCvsId();}}); $.extend($.jvChart,{getStylesheet : function(){ return new jvStylesheet();}}); return this.each( function() { this.elements = []; this.canvas = $.jvChart.createCanvas(this); this.selected = new jvGroup(this.canvas); //createImageMap(this); $(this).css({overflow:'hidden', position:'relative'}); var $d = this; $(this).mousemove(function (e) { if (!getMouseButton(e).left){return;} if (this.selected.size() > 1){ $.jvChart.dragMove($d, e); return false; } $(this.selected.getValues()).each( function(i) { if(this && this.state ){ var action = this.state.action; if (action == jvConstants.ACTION_MOVE){ $.jvChart.dragMove($d, e); }else if (action == jvConstants.END_POINT_MIDDLEBOTTOM){ $.jvChart.bottomResize($d, e); }else if (action == jvConstants.END_POINT_MIDDLETOP){ $.jvChart.topResize($d, e); } } }); return false; }).mouseup(function (e) { if (this.selected.size() > 1){ if (this.selected.state && this.selected.state.changed){ this.selected.reDraw(); } return false; } $(this.selected.getValues()).each( function(i) { if (this.state && this.state.changed){ this.reDraw(); }else{ this.unselect(); $d.selected.deleteElement(this); document.onselectstart=new Function ("return true"); } }); return false; }).mousedown(function (e) { $(this.selected.getValues()).each( function(i) { this.unselect(); $d.selected.deleteElement(this); }); }); }); }; $.fn.extend({ circle : function (x, y, r, color, width, fill, shadow, image) { return $.jvChart.drawCircle($(this).attr('paper'), x || 0, y || 0, r || 0, color, width, fill, shadow, image); }, insertEllipse : function (x, y, rx, ry, label) { var element = new jvEllipseElement($(this).attr('canvas'), x, y, rx, ry, label); $(this).attr('elements').push(element); return element; }, insertRectangle : function (x, y, w, h, r, label) { var element = new jvRectangleElement($(this).attr('canvas'), x, y, w, h, r, label); $(this).attr('elements').push(element); return element; }, insertEdge : function(source, target){ var element = new jvEdgeElement($(this).attr('canvas'), source, target); source.edges.push(element); target.edges.push(element); //$(this).attr('elements').push(element); return element; }, reDrawCanvas : function(){ var elements = $(this).attr('elements'); $(elements).each( function(i) { this.reDraw(); this.unselect(); }); } }); })(jQuery);
调用js
$(document).ready(function(){ $("#container").jvChart(300, 200); var v1 = $("#container").insertEllipse(10, 120, 80, 40, '椭圆'); var s = {}; s[jvConstants.STYLE_STROKECOLOR] = '#A0C88F'; v1.setStyle(s); var v2 = $("#container").insertRectangle(100, 20, 80, 40, 10, '矩形'); v2.setLabelLocation(jvConstants.LABEL_LOCATION_MIDDLE); var v4 = $("#container").insertEllipse(200, 100, 50, 50); var v3 = $("#container").insertRectangle(150, 180, 60, 40, 2); $("#container").insertEdge(v1, v2); $("#container").insertEdge(v2, v3); $("#container").insertEdge(v2, v4);/**/ });
container是一个div:
<div id="container" style="width:640px; height:400px; background-color:rgb(255,255,255); background-image:url('images/graph/grid.gif')"></div>