svg的js库

   很久没有写博客了,贴上这个月前一段关于动态创建svg的js库吧。

/**
	SVGObject 库针对于SVG封装部分功能
	为SVG脚本开发提供方便,后期会加入
	于VML兼容的封装,实现IE下面可以正
	常的执行
	@author: 追本溯源
	@time: 2015-5-5
*/

SVGObject = {version: '1.1'}

SVGObject.SVG_NS = 'http://www.w3.org/2000/svg';

SVGObject.XLINK_NS = "http://www.w3.org/1999/xlink";  

SVGObject.MAP_TRANS = {   //一些特殊的属性需要替换
	svgclass: 'class',
	svghref: 'href'
}

SVGObject.ARROW_ID = 'arrow_id';

SVGObject.get = function(el) {
	
	el = typeof el == 'string'? document.getElementById(el) : el;

	var svgEl = SVGObject.Element.prototype.findSpecilSvgElement(el);
	
	svgEl == null? svgEl = new SVGObject.Element(el) : svgEl;
	
	return svgEl;
	
}

SVGObject.svgHelper = function() {

	function getIdByDate() {

		var date = new Date();
		
		return 'svg_' + date.getTime();
	};

	function cloneObj(datas) {
		//数组对象涉及深拷贝
		var values;
		if(SVGObject.isObject(datas) || SVGObject.isArray(datas)) {
			values = SVGObject.isArray(datas)? [] : {};
		}
		for(var key in datas) {
			values[key] = datas[key];
		}
		return values;
	}


	/** 将原生的svg元素注册成封装的SVGElemeng*/
	function regToElement(el) {
	
		var svgEl = SVGObject.Element.prototype.findSpecilSvgElement(el);
		if(svgEl == null) {
			svgEl = new SVGObject.Element(el);
		}
		return svgEl;
	};
	return {
		reg2Element: regToElement,
		getId: getIdByDate,
		clone: cloneObj
	}

}();

SVGObject.apply = function(attr1, attr2) {
	attr1 = attr1 || {};
	if(SVGObject.isObject(attr2)) {    //浅拷贝
		for(var key in attr2) {
			attr1[key] = attr2[key];
		}
	}
	return attr1;
}

SVGObject.isObject = function(attr1) {

	return Object.prototype.toString.call(attr1) == '[object Object]';
}

SVGObject.isArray = function(attr) {
	
	return  Object.prototype.toString.call(attr) == '[object Array]';
}

SVGObject.extend = function(attr1, attr2, attr3) {
	
	if(SVGObject.isObject(attr2)) {  
		attr3 = attr2;
		attr2 = attr1;
		attr1 = attr3.constructor != Object.prototype.constructor? attr3.constructor : function() {
			attr2.apply(this, arguments);
		}
	}
	var tempFn = function() {};  
	tempFn.prototype = attr2.prototype;

	/** 采用中间方法防止attr2.prototype上属性被修改*/
    attr1.prototype = new tempFn();   
	attr1.prototype.constructor = attr1;

	attr1.prototype.superclass = attr2.prototype;
	SVGObject.apply(attr1.prototype,attr3);

	attr1.prototype.apply = function(obj) {
		SVGObject.apply(attr1,obj);	
	}
	// add more code here

	return attr1;
}


SVGObject.ComponentList = {
	

}

/**
	组件基类,所有图形都是基于该方法
	<rect id='moban_rect' x='0' y='0' width='50' height='30' fill='blue' fill-opacity='0.5'></rect>
*/

SVGObject.Component = function() {

	//数据拷贝,整理
	this.datas = SVGObject.svgHelper.clone(arguments[0] || {});
	
	SVGObject.apply(this,this.datas);

	this.initComponent();
	//this.addEvents('svgclick', 'svgmousemove', 'svgdblclick', 'svgmouseenter', 'svgmouseout');
	//this.superclass.addElements(this);
	SVGObject.Element.components[this.id] = this.cEl; //将该对象存放到一个集合
	
	//组件插入
	if(this.renderTo) {
		this.render(this.renderTo);
		delete this.renderTo;         //为的是不让下面设置参数的时候获取到该参数
	}

	this.addAttribute(this.datas);
}


SVGObject.apply(SVGObject.Component.prototype, {

	addAttribute: function(arg) { 

		if(this.cEl == null || this.cEl == 'undefined') {  //必须给该组件创建相应的SVGElement 才能增加属性
			return;
		}
		
		if(typeof arguments[0] == 'string') {   //暂时为 object 类型和 2个参数string类型的属性提供该功能
			var ary = [];
			arg = ary[argument[0]] = arguments[1];
		}

		for(key in arg) {
			this.cEl.addAttributeForEl(key,arg[key]); //具体的校验到SVGObject.Element提供的方法里面进行
		}
		
	},
	initComponent: function() {

		this.id = this.id? this.id : SVGObject.svgHelper.getId();

		/** 一些初始化属性需要在下面执行才能让正常运行*/
		if(this.cEl == 'undefined' || this.cEl == null) {
			
			var el = document.createElementNS(SVGObject.SVG_NS, this.typeName);
			this.cEl = SVGObject.svgHelper.reg2Element(el);
		}

	},
	
	getAttribute: function() {

	},

	render: function(renderTo) {  

		if(renderTo == null || renderTo == 'undefined') {
			return ;
		}
		this.renderTo = SVGObject.svgHelper.reg2Element(renderTo);
		this.renderTo.dom.appendChild(this.cEl.dom);
	}

})

SVGObject.EventManager = function() {
	

	return {
		attachListener: function(targetEl, ename, callbackFtn) {

			targetEl.addEventListener(ename, callbackFtn, false);
		},
		fireEvents: function(ename,element, evt) {
			var cacheElObj = this.findSpecilElCache(element);   //this指的是下边fireEvents.call()第一个参数作为作用域
			var listeners = cacheElObj.listeners[ename];
			for(var index = 0; index < listeners.length; index++) {
				var listen = listeners[index];
				element.firing = true;
				if(listen.call(element, evt) === false) {
					element.firing = false;
					return false;
				}
			}
			element.firing = false;
			return true;
		}
	
	
	};
}()


SVGObject.Element = function(el) {

	el = typeof el == 'string' ? SVGObject.getSVGEl().dom.getElementById(el) : el;
	
	if(el && !this.hasTargetElCache(el)) {
		 this.addElCache(el);
	}
	var temp = SVGObject.Element.svgElements[0];
	this.id = el.id ;
	this.dom = el ; 
}

SVGObject.Element.elCache = [];

SVGObject.Element.svgElements = [];

SVGObject.Element.components = {};

SVGObject.apply(SVGObject.Element.prototype, {
	addElCache: function(element) {  //el为原生的svg元素
		var nt = element.nodeName;
		var obj = {
			nametype: nt,
			el: element,
			data: [],        
			attrs: {},      //这个el所包含的属性
			listeners: {}
		}
		SVGObject.Element.elCache.push(obj);
		SVGObject.Element.svgElements.push(this);
		SVGObject.Element.components[this.id] = this;
	},
	addListener: function(ename, eFn, scope, option) {  //SVGObject.get('id').addListener('click',ftn);
	
		var tempthis = this;
		/*tempthis.events = tempthis.events || {};
		var listeners = tempthis.events[ename] || []; */
		scope = scope || tempthis;
		var targetEl = tempthis.dom;
		

		function callbackFtn(evt) {
			SVGObject.EventManager.fireEvents.call(tempthis,ename,tempthis.dom,evt);
		}

		this.addListenerAtElCache(ename, eFn);
		SVGObject.EventManager.attachListener(targetEl, ename, callbackFtn);
	},
	hasTargetElCache: function(element) {
		var len = SVGObject.Element.elCache.length;
		var array = SVGObject.Element.elCache;
		for(var index = 0; index < length; index++) {
			var obj = array[index];
			if(obj.el == element) {
				return true;
			}
		}
		return false;
	},
	findSpecilElCache: function(element) {
		element = element || this;
		var addr = SVGObject.Element.prototype.findSpecilElCacheAddr(element);
		if(addr == null) {
			return null;
		}
		return SVGObject.Element.elCache[addr];		
	},

	findSpecilElCacheAddr: function(element) {
		
		element = element || this;
		if(element.findSpecilElCacheAddr) {   //如果是SVGElement类型
			element = element.dom;
		}
		var len = SVGObject.Element.elCache.length;
		var array = SVGObject.Element.elCache;
		
		for(var index = 0; index < len; index++) {
			var obj = array[index];
			if(obj.el == element) {
				return index;
			}
		}
		return null;
	},
	findSpecilSvgElement: function(element) {
		
		element = element || this;
		if(element.findSpecilSvgElement) {
			return element;
		}
		var addr = SVGObject.Element.prototype.findSpecilElCacheAddr(element);
		if(addr == null) {
			return null;
		}
		return SVGObject.Element.svgElements[addr];
	},
	addListenerAtElCache: function(ename,eFn) {

		var cacheElObj = this.findSpecilElCache();
		if(cacheElObj == null) {
			return ;
		}
		cacheElObj.listeners[ename] = cacheElObj.listeners[ename] || [];
		if(this.firing) {
			cacheElObj.listeners[ename] = Array.prototype.slice.call(cacheElObj.listeners[ename],0);
		}
		cacheElObj.listeners[ename].push(eFn);
	},
	addAttributeForEl: function(attr, value) {
		
		if(/^svghref$/.test(attr)) {   //  对于href这种属性,前面有命名空间,这里暂时录入href

			attr = attr in SVGObject.MAP_TRANS ? SVGObject.MAP_NS[attr] : attr;
			this.addAttributeNSForEl(attr,value)

		}else {

			attr = attr in SVGObject.MAP_TRANS ? SVGObject.MAP_NS[attr] : attr;
			this.dom.setAttribute(attr, value);
		}
	},
	addAttributeNSForEl: function(attr, value) {

		attr = attr in SVGObject.MAP_TRANS ? SVGObject.MAP_NS[attr] : attr;
		this.dom.setAttribute(SVGObject.XLINK_NS, attr, value);

	},
	removeCurrentEl: function(el) {
		var parentEl = el.dom;
		parentEl.removeChild(this.dom); 
	}


});


SVGObject.SVGRect = SVGObject.extend(SVGObject.Component,{

	initComponent: function() {   //重写基类初始化方法 2015/5/6

		this.typeName = this.typeName || 'rect';

		SVGObject.SVGRect.prototype.superclass.initComponent.apply(this,arguments);
		
		/**   子类间的差异性 */

	
		
	},
	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6
		SVGObject.SVGRect.prototype.superclass.addAttribute.apply(this,arguments);
	},
	render: function(svgEl) {
		
		SVGObject.SVGRect.prototype.superclass.render.call(this,svgEl);
		
	}

})


/**
	Svg线条元素 2015/5/7。
*/

SVGObject.SVGLine = SVGObject.extend(SVGObject.Component, {


	initComponent: function() {  

		this.typeName = this.typeName || 'line';

		SVGObject.SVGLine.prototype.superclass.initComponent.apply(this,arguments);
		
		/**   子类间的差异性 */

	
		
	},

	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6
		SVGObject.SVGLine.prototype.superclass.addAttribute.apply(this,arguments);
	},

	render: function(svgEl) {
		
		SVGObject.SVGLine.prototype.superclass.render.call(this,svgEl);
		
	}
});

/** 
	SVG path 元素封装 
	@time 2015/5/7
*/
SVGObject.SVGPath = SVGObject.extend(SVGObject.Component, {

	initComponent: function() {  

		this.typeName = this.typeName || 'path';

		SVGObject.SVGPath.prototype.superclass.initComponent.apply(this,arguments);
		
		/**   子类间的差异性 */

	
		
	},

	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6
		SVGObject.SVGPath.prototype.superclass.addAttribute.apply(this,arguments);
	},

	render: function(svgEl) {
		
		SVGObject.SVGPath.prototype.superclass.render.call(this,svgEl);
		
	}

});

/**
	SVG defs 元素封装
	@time 2015/5/7
*/

SVGObject.SVGDefs = SVGObject.extend(SVGObject.Component, {

	initComponent: function() {  

		this.typeName = this.typeName || 'defs';

		SVGObject.SVGDefs.prototype.superclass.initComponent.apply(this,arguments);
		
		/**   子类间的差异性 */	
		
	},

	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6
		SVGObject.SVGDefs.prototype.superclass.addAttribute.apply(this,arguments);
	},

	render: function(svgEl) {
		
		SVGObject.SVGDefs.prototype.superclass.render.call(this,svgEl);
		
	}

});

/**
	SVG marker元素封装
*/
SVGObject.SVGMarker = SVGObject.extend(SVGObject.Component, {

	initComponent: function() {  

		this.typeName = this.typeName || 'marker';

		SVGObject.SVGMarker.prototype.superclass.initComponent.apply(this,arguments);
		
		/**   子类间的差异性 */	
		
	},

	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6
		SVGObject.SVGMarker.prototype.superclass.addAttribute.apply(this,arguments);
	},

	render: function(svgEl) {
		
		SVGObject.SVGMarker.prototype.superclass.render.call(this,svgEl);
		
	}

}); 


/** 
	SVG自定义封装的箭头组合图形
	@time 2015/5/8

*/

SVGObject.SVGArrow = SVGObject.extend(SVGObject.Component, {
	
	initComponent: function() {  

		this.arrowEl = this.arrowEl || SVGObject.Element.components[SVGObject.ARROW_ID];

		if(this.arrowEl == 'undefined' || this.arrowEl == null) {

			this.defsEl = this.defEl? this.defEl : new SVGObject.SVGDefs({ renderTo: document.documentElement }).cEl;

			this.markerEl = this.markerEl? this.markerEl : new SVGObject.SVGMarker({
																renderTo: this.defsEl,
																id: SVGObject.ARROW_ID,
																refX: '0',
																refY: '0',
																markerWidth: '15',
																markerHeight: '15',
																orient: 'auto',
																viewBox: '0,-3,10,6'
															}).cEl;

			this.path = this.path? this.path : new SVGObject.SVGPath({
													renderTo: this.markerEl,
													d: 'M0 -3 L0 3 L10 0',
													fill: this.fill || 'black',
													'stroke-width': '0',
													style: this.style || ''
												}).cEl;

		}
		
		//<line class="link" marker-end="url(#arrow)" x1="0" y1="0" x2="80" y2="80" stroke='black' fill='black' stroke-width='1' ></line>
		
		
		this.typeName = this.typeName || 'line';
		this.renderTo = this.renderTo || document.documentElement;

		SVGObject.SVGArrow.prototype.superclass.initComponent.apply(this,arguments);


		/**   子类间的差异性 */	
		
	},

	addAttribute: function(argu) {  //重写基类属性添加方法  2015/5/6

		argu.x1 = this.arrowX1; delete argu.arrowX1;
		
		argu.y1 = this.arrowY1; delete argu.arrowY1;
		
		argu.x2 = this.arrowX2; delete argu.arrowX2;
		
		argu.y2 = this.arrowY2; delete argu.arrowY2;
		
		argu['marker-end'] = 'url(#' + SVGObject.ARROW_ID + ')';
		
		
		

		// <line class="link" marker-end="url(#arrow)" x1="0" y1="0" x2="80" y2="80" stroke='black' fill='black' stroke-width='1' ></line>
		
		SVGObject.SVGArrow.prototype.superclass.addAttribute.call(this, argu);

	},

	render: function(svgEl) {
		
		SVGObject.SVGArrow.prototype.superclass.render.call(this,svgEl);
		
	}



});
















xml调用方式

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
                     "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width='100%' height='100%'  onload='init(evt)'
     version="1.1"
     xmlns="http://www.w3.org/2000/svg"
	 xmlns:xlink='http://www.w3.org/1999/xlink'>
  <script xlink:href="SVGObject.js" language="JavaScript"/>
  <script type="text/ecmascript"><![CDATA[
		
	var init = function() {
			var sharp;
			var curEl, preEl; //当前El 上一个El
			var qx,qy,zx,zy;
			var mousedown;
			var svgDoc,svgRoot,moban_rect,moban_circle,moban_line;
			//工具模板颜色释放
			var releaseOther = function(cs1,cs2) {

				cs2 = typeof cs2 == 'string'? SVGObject.get(cs2) : cs2;
				var childNodes = cs2.dom.childNodes;
				
				for(var key in childNodes) {
					
					if(childNodes[key].nodeType == 1) {
						
						if(childNodes[key].id != cs1) {
							
							if(childNodes[key].id == 'moban_arrow') {
								childNodes[key].setAttribute('fill','blue');
								document.getElementById('moban_arrow1').setAttribute('stroke','blue');
								return;
							}
							childNodes[key].setAttribute('fill','blue');
						}else {
							
							if(childNodes[key].id == 'moban_arrow') {
								document.getElementById('moban_arrow1').setAttribute('stroke','black');
								childNodes[key].setAttribute('fill','black');
							}else {
								childNodes[key].setAttribute('fill','black');
							}
						
						}
						
					}
				}
			}
			//初始化相关属性
			constructorOne = function(evt) {
				svgRoot = SVGObject.get(document.documentElement);
				moban_rect = SVGObject.get('moban_rect');
				moban_yuanjiao = SVGObject.get('moban_yuanjiao');
				moban_arrow = SVGObject.get('moban_arrow1');
			}
				
			return function(evt) {

				constructorOne(evt);
				
				moban_rect.addListener('click',function() {
					
					releaseOther('moban_rect', 'moban');
					sharp = 'rect';
				
				});
		
				moban_yuanjiao.addListener('click',function() {
				
					releaseOther('moban_yuanjiao', 'moban');
					sharp = 'yuanjiao';
				
				});
					
				moban_arrow.addListener('click', function() {
				
					releaseOther('moban_arrow', 'moban');
					sharp = 'arrow';
				
				});

				svgRoot.addListener('mousedown',function(evt) {

						qx = evt.clientX;
						qy = evt.clientY;
						mousedown = true;

					
				});
				svgRoot.addListener('mousemove', function(evt) {
				
					var flag1 = sharp == undefined || sharp == '' || sharp == null || sharp == 'undefine';
					
					//有图形且点击
					if(!sharp || !mousedown ) {
						return ;                         //上边判断curEl是防止,画好一个元素,sharp不为空,继续移动而可以执行下面代码
					}
				
					if(preEl) { //null undefined都为false
						preEl.removeCurrentEl(svgRoot);  //js库SVGObject提供移除的方法
					}
					zx = evt.clientX;
					zy = evt.clientY;
					
					switch(sharp) {

					  case 'rect':  
									curEl = new SVGObject.SVGRect({   //SVGObject库提供计算点到点距离的方法
										'x': qx,
										'y': qy,
										'width': zx - qx,
										'height': zy - qy,
										'style': 'stroke: "blue"; stroke: "1"; fill: "black" '
									});
									break;

					  case 'yuanjiao': 
									curEl = new SVGObject.SVGRect({   //SVGObject库提供计算点到点距离的方法
										'x': qx,
										'y': qy,
										'rx': '20',
										'ry': '20',
										'width': zx - qx,
										'height': zy - qy,
										'style': 'stroke: "blue"; stroke: "1"; fill: "black" '
									});
									break;
							   
					  case 'arrow':  
									curEl = new SVGObject.SVGArrow({   //SVGObject库提供计算点到点距离的方法
										'arrowX1': qx,
										'arrowY1': qy,
										'arrowX2': zx,
										'arrowY2': zy,
										'style': 'fill: black',
										'stroke': 'black',
										'stroke-width': '1'
									});
									break;
					}
					
					curEl.render(svgRoot.dom);  //SVGObject类库中重载父类render() 实现各自的功能
					preEl = curEl.cEl;
	

				});	

				svgRoot.addListener('mouseup', function() {
					preEl = null;
					curEl = null;
					mousedown = false;
				});
			}

		}();                   
  ]]></script>
  <defs id='moban' >
	<rect id='moban_rect' x='0' y='0' width='50' height='30' fill='blue' fill-opacity='0.5'></rect>
	<rect id='moban_yuanjiao'  x='60' y='0' rx='7' ry='7' width='50' height='30' fill='blue' fill-opacity='0.5'></rect>
	 <marker id="moban_arrow" refX="0" refY="0" markerWidth="15" markerHeight="15" orient="auto" viewBox="0, -3, 10, 6" >
            <path d="M0 -3 L0 3 L10 0"  stroke-width='0'></path>
      </marker>
  </defs>
  <use xlink:href='#moban_rect'></use>
  <use xlink:href='#moban_yuanjiao'></use>
  <line id="moban_arrow1" marker-end="url(#moban_arrow)" x1="120" y1="15" x2="150" y2="15" stroke='blue' fill='blue' stroke-width='2' ></line>
</svg>


上边的js库看起来很熟悉是吗,其实我只读了Ext一部分源码,思维被影响了,应该读更多的优秀的js库的。我现在工作是基于java后台开发,前端兴趣所至,写的不好的地方,请指教


你可能感兴趣的:(svg的js库)