`

D3的使用(Flow事件IP(PORT)关系可视化实现)

阅读更多
图片:





















[align=left]
 /**
 * 基于D3关系分布图
 * @author wang xiu fu
 */
Ext.define('shyl.view.flowevent.IPPortRelationView', function() {
	var Aesset = {
			notEmpty: function(o, message) {
				if (o === null || o === undefined || (Ext.isArray(o) && o.length === 0) || (Ext.isString(o) && o === '')) {
					alert(message);
					Ext.Error.raise(message);
				}
			}
		},
		xyRe = /\(((-)*([(\d)\.]+)){1}(?:,)((-)*([(\d)\.]+)){1}\)/g,
		getXYFromTranslate = function(translate) {
			if (!translate) {
				return;
			}
			var res, fn = function(m1,m2, m3, m4, m5, m6, m7) {res = [parseInt(m2), parseInt(m5)];};
			translate = translate.replace(/\s/g, '');
			translate.replace(xyRe, fn);
			return res;
		},
		replaceStrTemplate = function(str, v) {
			for (var pro in  v) {
				if (v.hasOwnProperty(pro)) {
					str = str.replace('{'+ pro +'}', v[pro]);
				}
			}
			return str;
		},
		toFix = function(d, n) {
			var e = Math.pow(10, n);
			return Math.floor(d * e) / e;
		},
		delayFn = function(fn, scope, timeout, args) {
			if (fn.delayTimeoutId) {
				clearTimeout(fn.delayTimeoutId);
			}
			fn.delayTimeoutId = setTimeout(function() {
				if (args) {
					fn.apply(scope, args);
					return;
				}
				fn.call(scope);
			}, timeout)
		},
		calculateAxisLabelFn = function(v) { //提供一个简单的文本实际宽度计算函数
			v = String(v);
			var dotcount = v.split('.').length - 1;
			return (v.length - dotcount) * 7 + dotcount*4;
		},
		currentSelectScale, currentSelectLine;
		
	return {
		extend: 'Ext.Component',
		alias: 'widget.ipportrelationview',
		surfaceCls: 'surface-cls',
		titleCls: 'surface-title-cls',
		surfaceAxisLeftCls: 'surface-axis-left-Cls',
		surfaceAxisLeftLabelCls: 'surface-axis-left-label-Cls',
		surfaceAxisRightCls: 'surface-axis-right-Cls',
		surfaceAxisRightLabelCls: 'surface-axis-right-label-Cls',
		lineItemCls: 'line-item-cls',//线的默认样式
		emptyTextCls: 'empty-text-cls',
		displayLegendCls: 'display-legend-cls',
		/**
		 * axis配置:
		 * {
		 *   whenLeft: function(index, total , value, fieldName, data, dataIndex) {} //用户分组
		 *   vField: 
		 *   rField: 
		 *   leftTitle:
		 *   rightTitle:  
		 * }
		 */
		axis: null,
		//data config
		store: null, //store
		legend: null, // { type: ''  }如果为false,则不显示legend信息,
		emptyText: '未加载到数据',
		
		//loadMsg
		loadingText: '加载中....',
		
		initComponent: function() {
			var me  = this,
				bind = Ext.bind,
				tipButtonSettings = this.tipButtonSettings || {},
				loadMsgCfg;
			loadMsgCfg = {
                target: this,
                msg: me.loadingText,
                msgCls: me.loadingCls,
                useMsg: true,
                store: this.store
		     };
			me.callParent(arguments);
			
			me.loadMask = new Ext.LoadMask(loadMsgCfg);
			
			//header高度
			this.headerHeight = this.headerHeight || 80;
			//setup axis
			this.setupAxis();
			
			tipButtonSettings.settings = tipButtonSettings.settings || {};	
			tipButtonSettings.settings.data = [1, 2, 3];
			tipButtonSettings.settings.colors = ['#E0EEE0', '#CD8162', '#FF0000'];
			tipButtonSettings.settings.expression = [{lessthan: [10000000, 0.0004]}, {lessthan: [50000000, 0.002]}];
			this.tipButtonSettings = tipButtonSettings;
			me.mon(this.store, {
				refresh: bind(me.onStoreLoad, me)
			});
			
			this.addEvents({
				onLinesClick: true
			})
		},
		
		setupAxis: function() {
			var me = this,
				axis = this.axis || {};
			if (!axis.whenLeft || !Ext.isFunction(axis.whenLeft)) {
				axis.whenLeft = function(index, total , value, fieldName, data, dataIndex) {
					return  index % 2 === 0;
				}
			}
			Aesset.notEmpty(axis.vField, 'not define "vField" of axis');
			Aesset.notEmpty(axis.rField, 'not define "rField" of axis');
			
			axis.leftTitle = axis.leftTitle || '左';
			axis.rightTitle = axis.rightTitle || '右';
			axis.data = {leftTotal: 0, rightTotal: 0, total: 0,	left: [], right: [], data: []};
			axis.leftSpace = axis.leftSpace || 100;
			axis.leftRightSpace = axis.leftRightSpace || 300;
			axis.leftSpritColor = axis.leftSpritColor || '#f0a50a';
			axis.rightSpritColor = axis.rightSpritColor || '#c20024';
			this.axisLableSpace = this.axisLableSpace || 30;
		},
		onScrollEvent: function() {
			delayFn(this.updateTipButtonPosition, this, 50);
			delayFn(this.showPortRelationSprite, this, 50);
		} ,
		afterRender: function() {
			var me = this;
			me.callParent(arguments);
			//监听scroll事件
			this.getEl().addListener('scroll', me.onScrollEvent, me);
		},
		
		onStoreLoad: function(store, eOpts) {
			this.hidePortRelationSprite();
			//清理缓存数据
			this.axis.data = {leftTotal: 0, rightTotal: 0, total: 0,	left: [], right: [], data: []};
			var datas = store.data;
			//格式化数据
			this.formatDatas(datas);
			//创建Surface
			this.createSurface();
			if (!datas|| datas.length === 0) {
				this.showEmptyText();
			} else {
				this.hideEmptyText();
			}
			this.loadMask.show();
			this.loadMask.msgTextEl.update('渲染中...');
			//格式化数据
			this.onRefresh();
		},
		showEmptyText: function() {
			var surface = this.surface,
				bbox, centerX, emptyTextSpiteWidth;
			if (!this.emptyTextSpite) {
				this.emptyTextSpite = surface.append('svg:g');
				this.emptyTextSpite.append('svg:text')
					.text(this.emptyText)
				    .style('font-size', '12px')
				    .style('font-family', 'Arial')
				    .style('fill',  '#FFF')
					.attr('class', this.emptyTextCls);
			}
			this.createSurface();
			bbox = this.getBBox();
			centerX = bbox.width/2;
			//获取emptyTextSpite的宽度
			emptyTextSpiteWidth = this.emptyTextSpite.select('text')[0][0].offsetWidth;
			this.emptyTextSpite.attr('transform', 'translate(' + (centerX-(emptyTextSpiteWidth/2)) + ', ' + 100 + ')').style('display', '');
		},
		hideEmptyText: function() {
			if (this.emptyTextSpite) {
				this.emptyTextSpite.style('display', 'none');
			}
		},
		
		formatDatas: function(datas) {
			var me = this,
				axis = this.axis,
				whenLeft = axis.whenLeft,
				axisDatas = axis.data, //axis.data = {leftTotal: 0, rightTotal: 0, total: 0,	left: [], right: [], data: []};
				vfield = axis.vField,
				rfield = axis.rField,
				i, len, record, count = 0, leftcount = 0, rightcount = 0, tempDataCache = {};
			if (this.drawStatus == 1) {
				axisDatas.leftTotal = 0;
				axisDatas.rightTotal = 0;
				axisDatas.left = [];
				axisDatas.right = [];
				axisDatas.data = [];
			}
			for (i=0, len = datas.length; i<len; i++) {
				record = datas.get(i);
				if (!tempDataCache[record.get(vfield)]) {
					axisDatas.data.push({name: record.get(vfield), field: vfield, data: record, dataIndex: i});
					tempDataCache[record.get(vfield)] = true;
					count++;
				}
				if (!tempDataCache[record.get(rfield)]) {
					axisDatas.data.push({name: record.get(rfield), field: rfield, data: record, dataIndex: i});
					tempDataCache[record.get(rfield)] = true;
					count++;
				}
			}
			axisDatas.total = count; //总个数
			for (i=0; i<count; i++) {
				record = axisDatas.data[i];
				if (whenLeft.call(this, i, count , record.name, record.field, record.data, record.dataIndex)) {
					record.position = 1;
					axisDatas.left.push(record);
					leftcount++;
				} else {
					record.position = 2;
					axisDatas.right.push(record);
					rightcount++;
				}
			}
			axisDatas.leftTotal = leftcount;
			axisDatas.rightTotal = rightcount;
		},
		
		/**
		 * 创建SVG DOM 
		 */
		createSurface: function() {
			var me = this,
				axis = this.axis,
				axisLableSpace = axis.axisLableSpace || 25,
				headerHeight = this.headerHeight || 80,
				el = me.getEl(),
				bbox = this.getBBox(),
				floor = Math.floor,
				axis = this.axis,
				axisDatas = axis.data, //axis.data = {leftTotal: 0, rightTotal: 0, total: 0,	left: [], right: [], data: []};
				bodyDom = el.dom,
				max = Math.max,
				surface, maxcount, realHeight, necessaryHeight, axisLableTopY;
			realHeight = bbox.height - 2 - headerHeight;
			maxcount = max(axisDatas.leftTotal, axisDatas.rightTotal);
			//计算svg的总高度
			necessaryHeight = maxcount * axisLableSpace;
			this.axisLableTopY = headerHeight;
			if (necessaryHeight < realHeight) {
				axisLableTopY = this.axisLableTopY = headerHeight + floor((realHeight - necessaryHeight) / 2);
			}
			realHeight = necessaryHeight + headerHeight;
			if (!this.surface) {
				surface = d3.select(bodyDom).append('svg')
					.attr('class', this.surfaceCls)
				me.surface = surface;
			}
			axis.axisLableSpace = axisLableSpace;
			this.headerHeight = headerHeight;
			
			this.surface.svgHeight = (realHeight < (bbox.height - 2) ? (bbox.height - 2) : realHeight);
			me.autoSizeSurface(this.surface.svgHeight);
		},
		
		/**
		 * 获取绘制环境容器的size信息
		 */
		getBBox: function() {
			var el = this.getEl(),
				innerSpace = this.innerSpace || 5;
			this.innerSpace = innerSpace;
			return {
				x: innerSpace,
				y: innerSpace,
				width: el.getWidth(),
				height: el.getHeight(),
				scrollTop: el.getScrollTop()
			}
		},
		
		/**
		 *  动态设置当前svg dom 的width 、height
		 */
		autoSizeSurface: function(height, width) {
			var me = this,
			box = me.getBBox();
			height || (height = box.height);
			width || (width = box.width);
			me.surface.attr('width', width-25)
					.attr('height', height);
		},
		
		onRefresh: function() {
			this.setTitle(this.title);
			//this.showTipButton();
			//this.hideTipButton();
			this.redraw();
			this.loadMask.hide();
		},
		
		redraw: function() {
			this.drawAxis();
			this.drawLines();
			this.drawLegend();
			this.drawStatus = 1;
		},
		
		setTitle: function(title) {
			var titleSprite = this.titleSprite;
			if (!title) {
				return;
			}
			if (!titleSprite) {
				titleSprite = this.titleSprite = this.surface.append('svg:g');
				titleSprite.append('svg:text')
					.text('')
					.attr('class', this.titleCls)
				    .style('font-size', '14px')
				    .style('font-weight', 'bold')
				    .style('font-family', 'Arial');
			}
			titleSprite.attr('transform', 'translate(10, 20)');
			d3.select(titleSprite.selectAll('text')[0][0]).text(title || '');
		},
		//绘制图例用于显示明细信息
		drawLegend: function() {
			if (!this.legendSprite) {
				this.legendSprite = this.surface.append('svg:g').style('display', 'none');
				this.legendSprite.append('svg:rect')
					.attr('x', 0)
					.attr('y', 0)
					.attr('width', 100)
					.attr('height', 20)
					.attr('rx', 0)
					.attr('ry', 0)
					.attr('fill', '#EEE9E9')
					.attr('stroke-width', 0.5)
					.attr('stroke', '#000');
			}
		},
		showLegend: function(pos) {
			var axis = this.axis,
				legend = this.legend,
				minLegendWidth = legend.minWidth || 100,
				displayLabels = legend.displayLabels,
				svgHeight = this.surface.svgHeight,
				displayLegendCls = this.displayLegendCls,
				allTexts, maxWidth = minLegendWidth,
				rightx = axis.rightx,
				max = Math.max,
				i, len, legendHeight, legendSpriteDom;
			legend.minWidth = minLegendWidth;
			legendSpriteDom = this.legendSprite[0][0];
			//解决覆盖问题
			this.legendSprite.remove();
			this.surface[0][0].appendChild(legendSpriteDom);
			//获取legend的宽度
			allTexts = this.legendSprite.selectAll('text.' + displayLegendCls);
			for (i=0, len=allTexts.length; i<len; i++) {
				maxWidth = max(maxWidth, allTexts[i][0].offsetWidth);
			}
			maxWidth = maxWidth + 40; 
			this.legendSprite.style('display', '');
			if (pos[0] > (rightx - 50)) {
				pos[0] = pos[0] - maxWidth;
			} 
			legendHeight = (displayLabels.length + 1)*20;
			if ((parseInt(pos[1]) + parseInt(legendHeight)) > svgHeight) {
				pos[1] = svgHeight - legendHeight -30;
			}
			this.legendSprite.attr('transform', 'translate('+ pos[0] +', '+ pos[1] +')');
			this.legendSprite.select('rect').attr('width', maxWidth).attr('height', legendHeight);
		},
		hideLegend: function() {
			this.legendSprite.style('display', 'none');
		},
		updateLegendContent: function(v) {
			var me = this,
				surface = this.surface,
				legend = me.legend,// {displayLabels:[]}
				displayLabels = legend.displayLabels || [],
				displayLegendCls = this.displayLegendCls,
				legendSprite = this.legendSprite,
				legendRender = legend.rendeFn,
				axis = this.axis,
				v = function(){
					return legendRender(v, axis.coordinateList[v.name].lines);
				}(),
				singalX = 25, 
				singalY = 20,
				isArray = Ext.isArray,
				x, len, item, ii, len1, preText, allTexts;
			legend.displayLabels = displayLabels;
			if (!legend.initialize) { //未初始化
				for (i=0, len=displayLabels.length; i<len; i++) {
					item = displayLabels[i];
					legendSprite.append('svg:rect')
					.attr('x', 7)
					.attr('y', singalY - 10)
					.attr('width', 10)
					.attr('height', 10)
					.attr('fill', '#ff8809')
					legendSprite.append('svg:text')
						.attr('x', singalX)
						.attr('y', singalY)
						.text('')
						.attr('class', displayLegendCls);
					singalY += 20;
				}
				legend.initialize = true;
			}
			
			allTexts = legendSprite.selectAll('text.' + displayLegendCls);
			for (i=0, len=allTexts[0].length; i<len; i++) {
				d3.select(allTexts[0][i]).text(replaceStrTemplate(displayLabels[i], v));
			}
		},
		/**
		 * 绘制线
		 */
		drawLines: function() {
			var me = this,
				abs = Math.abs,
				box = me.getBBox(),
				storeDatas = this.store.data,
				arrayDatas = [],
				axis = this.axis,
				coordinateList = axis.coordinateList,
				series = this.series || {},
				tipButtonSettings = this.tipButtonSettings,//tipButtonSettings.settings.colors = ['#E0EEE0', '#CD8162', '#FF0000'];
				decideLineColor = function(d, i) {
					var rgbs = coordinateList.rgbs, fn;
					if (!rgbs ) {
						rgbs = coordinateList.rgbs = {};
					}
					rgbs[i] = '#3D3D3D';
					if ((fn = series.decideLineColor) && Ext.isFunction(fn)) {
						rgbs[i] = fn(d, i, tipButtonSettings.settings.colors, tipButtonSettings.settings.expression);
					}
					return rgbs[i];
				},
				pi = Math.PI,
				cos = Math.cos,
				sin = Math.sin,
				leftRightSpace = axis.leftRightSpace,
				axisDatas = axis.data,
				axisLableTopY = this.axisLableTopY,
				vfield = axis.vField,
				rfield = axis.rField,
				lines,
				diagonal = d3.svg.diagonal()
					.source(function(d) {
						var coordxy = coordinateList[d.get(vfield)];
						return {x: coordxy.x, y: coordxy.y}
					})
					.target(function(d) {
						var coordxy = coordinateList[d.get(rfield)];
						return {x: coordxy.x, y: coordxy.y}
					})
					.projection(function(d, index, _arrayObj) {
						var spoint = _arrayObj[0],
							dpoint = _arrayObj[3],
							cpoint, arrowX, arrowY, arrowL, isRight, randomNum;
						randomNum = (Math.random()*10000)%(abs(leftRightSpace/5)) + 200;
						if (spoint.x == dpoint.x) { //同一边
							_arrayObj[1].x = (spoint.x == axis.rightx) ? spoint.x - 20 : spoint.x + 20;
							if (spoint.y < dpoint.y ) {
								_arrayObj[1].y =  (spoint.y - axisLableTopY < 20) ? spoint.y : (spoint.y - 20);
							} else {
								_arrayObj[1].y =  (spoint.y + 20);
							}
							_arrayObj[2].x = dpoint.x + (dpoint.x == axis.rightx ? (-1)*randomNum : randomNum);
							_arrayObj[2].y = dpoint.y;
						} else { //不同边
							_arrayObj[1].x = spoint.x + (spoint.x == axis.rightx ? (-1)*randomNum : randomNum)
							_arrayObj[1].y = spoint.y;
							_arrayObj[2].x = dpoint.x + (dpoint.x == axis.rightx ? (-1)*randomNum : randomNum)
							_arrayObj[2].y = dpoint.y;
						}
						
						//加入箭头
						if (index == 3) {
							arrowX = 8 * cos(pi/6);
							arrowY = 8 * sin(pi/6);
							isRight = (d.x == axis.rightx);
							arrowX  = (isRight ? d.x - arrowX : d.x + arrowX);
							arrowL = 'L'+ arrowX +','+ (d.y-arrowY) +'M'+ d.x +','+ d.y +'L'+ arrowX +',' + (d.y+arrowY);
							return [d.x, d.y + arrowL];
						}
						return [abs(d.x) + 0.5, abs(d.y) + 0.5];
					});
				//coordinateList[record.name] = {x: record.x, record.y, data: record.data};
			this.surface.selectAll('path.' + me.lineItemCls).on('mouseover', null).on('mouseout', null).remove();
			for (var i=0; i<storeDatas.length; i++) {
				arrayDatas.push(storeDatas.get(i));
			}
			lines = this.surface.selectAll('path.' + me.lineItemCls)
				.data(arrayDatas)
				.enter()
				.append('svg:path')
				.attr('class', me.lineItemCls)
				.attr('d', diagonal)
				.attr('stroke', decideLineColor)
				.attr('fill', 'none')
				.attr('stroke-width', 1)
				.style('cursor', function(d, i) {
					//关联线与点的关系
					coordinateList[d.get(vfield)].lines.push(i);
					coordinateList[d.get(rfield)].lines.push(i);
					coordinateList[i] = [d.get(vfield), d.get(rfield)];
					return 'pointer';
				})
				.on('mouseover', function(d, i) {
					d3.select(lines[0][i]).style('stroke', (series.mouseOverColor || 'rgb(109,152,36)'));
				})
				.on('mouseout', function(d, i) {
					d3.select(lines[0][i]).style('stroke', coordinateList.rgbs[i]);
				}).
				on('click', function(d, i) {
					me.showPortRelationSprite();
					delayFn(me.onLinesClick, me, 200, [d, i]);
				})
		},
		onLinesClick: function(d, i) {
			this.fireEvent('onLinesClick', this, d, i);
		},
		/**
		 * 绘制点
		 */
		drawAxis: function() {
			var me = this,
				axis = this.axis,
				alignCenter = axis.alignCenter || false,
				leftSpace = axis.leftSpace,
				coordinateList = axis.coordinateList,
				leftRightSpace = axis.leftRightSpace,
				axisLableSpace = axis.axisLableSpace,
				leftSpritColor = axis.leftSpritColor,
				rightSpritColor = axis.rightSpritColor,
				series = this.series || {},
				headerHeight = this.headerHeight,
				axisLableTopY = this.axisLableTopY || headerHeight,
				box = me.getBBox(),
				axisDatas = axis.data, //axis.data = {leftTotal: 0, rightTotal: 0, total: 0,	left: [], right: [], data: []};
				xfn = function(d) {
					return d.lx;
				},
				yfn = function(d) {
					return d.ly;
				},
				lineItemCls = me.lineItemCls,
				handerFocusLines = function(name, isFocus, otherHidden) {
					var lines = axis.coordinateList[name].lines,
						allLines = d3.selectAll('path.' + lineItemCls)[0],
						i, len;
					for (i=0, len=allLines.length; i<len; i++) {
						d3.select(allLines[i]).style('display', (otherHidden ? 'none' : ''));
					}
					for (i=0, len=lines.length; i<len; i++) {
						d3.select(allLines[lines[i]]).style('stroke', (isFocus ? (series.mouseOverColor || 'rgb(109,152,36)') : coordinateList.rgbs[lines[i]])).style('display', '');
					}
				},
				textWidth, i, len, record, svgPathD, svgGs, datas, coordinateList;
				
			this.surface.selectAll('path.' + this.surfaceAxisLeftCls).remove();
			this.surface.selectAll('path.' + this.surfaceAxisRightCls).remove();
			this.surface.selectAll('g.' + this.surfaceAxisLeftLabelCls).remove();
			this.surface.selectAll('g.' + this.surfaceAxisRightLabelCls).remove();
			if (alignCenter) {
				leftSpace = ((box.width - leftRightSpace) / 2);
			}
			//绘制title
			if (!axis.leftTitleSprit) {
				axis.leftTitleSprit = this.surface.append('svg:g');
				axis.leftTitleSprit.append('svg:rect')
					.attr('x', 0)
					.attr('y', 0)
					.attr('width', 150)
					.attr('height', 20)
					.attr('rx', 0)
					.attr('ry', 0)
					.attr('fill', 'none')
					.attr('stroke-width', 1)
					.attr('stroke', '#f0a50a')
				axis.leftTitleSprit.append('svg:circle')
					.attr('cx', 15)
					.attr('cy', 10)
					.attr('r', 4)
					.attr('fill', '#f0a50a')
				axis.leftTitleSprit.append('svg:text')
					.text(axis.leftTitle)
					.style('font-size', '11px')
					.attr('x', 25)
					.attr('y', 15)
					.attr('fill', '#f0a50a');
			}
			if (!axis.rightTitleSprit) {
				axis.rightTitleSprit = this.surface.append('svg:g');
				axis.rightTitleSprit.append('svg:rect')
					.attr('x', 0)
					.attr('y', 0)
					.attr('width', 150)
					.attr('height', 20)
					.attr('rx', 0)
					.attr('ry', 0)
					.attr('fill', 'none')
					.attr('stroke-width', 1)
					.attr('stroke', '#c20024')
				axis.rightTitleSprit.append('svg:circle')
					.attr('cx', 15)
					.attr('cy', 10)
					.attr('r', 4)
					.attr('fill', '#c20024')
				axis.rightTitleSprit.append('svg:text')
					.text(axis.rightTitle)
					.style('font-size', '11px')
					.attr('x', 25)
					.attr('y', 15)
					.attr('fill', '#c20024');
			}
			
			//计算axis title的宽度 
			axis.leftx = (leftSpace + 10);
			axis.rightx = (leftSpace + leftRightSpace);
			this.leftSpace = leftSpace;
			axis.leftRightSpace = leftRightSpace;
			
			textWidth = axis.leftTitleSprit.select('text')[0][0].offsetWidth + 40;
			axis.leftTitleSprit.select('rect').attr('width', textWidth);
			axis.leftTitleSprit.attr('transform', 'translate('+ (axis.leftx - textWidth) +', 40)');
			
			textWidth = axis.rightTitleSprit.select('text')[0][0].offsetWidth + 40;
			axis.rightTitleSprit.select('rect').attr('width', textWidth);
			axis.rightTitleSprit.attr('transform', 'translate('+ (axis.rightx) +', 40)');
			coordinateList = axis.coordinateList = {}; 
			//draw left
			svgPathD = 'M' + axis.leftx + ','+ axisLableTopY +'L';
			for (i=0, len=axisDatas.left.length; i<len; i++) {
				record = axisDatas.left[i];
				record.x = axis.leftx;
				record.y = axisLableTopY + (i*axisLableSpace);
				record.lx = (10 + (calculateAxisLabelFn(record.name)))*(-1);
				record.ly = record.y;
				coordinateList[record.name] = {x: record.x, y: record.y, data: record.data, lines: []};
				svgPathD = svgPathD + (record.x + 0.5) + ',' + (record.y+ 0.5) +'M'+ (record.x+ 0.5) +','+ (record.y+ 0.5) + 'L'+ (record.x-10 + 0.5) +',' + (record.y+ 0.5) + 'M' + (record.x+ 0.5) + ',' + (record.y+ 0.5);
				if (i < (len-1)) {
					svgPathD = svgPathD + 'L';
				}
			}
			
			this.surface.append('svg:path').attr('d', svgPathD).attr('fill', 'none').attr('stroke', leftSpritColor).attr('stroke-width',1).attr('class', this.surfaceAxisLeftCls);
			svgPathD = 'M' + axis.rightx + ','+ axisLableTopY +'L';
			for (i=0, len=axisDatas.right.length; i<len; i++) {
				record = axisDatas.right[i];
				record.x = axis.rightx;
				record.y = axisLableTopY + (i*axisLableSpace);
				record.lx = 10;
				record.ly = record.y;
				coordinateList[record.name] = {x: record.x, y: record.y, data: record.data, lines: []};
				svgPathD = svgPathD + (record.x + 0.5) + ',' + (record.y+ 0.5) +'M'+ (record.x+ 0.5) +','+ (record.y+ 0.5) + 'L'+ (record.x+10 + 0.5) +',' + (record.y+ 0.5) + 'M' + (record.x+ 0.5) + ',' + (record.y+ 0.5);
				if (i < (len-1)) {
					svgPathD = svgPathD + 'L';
				}
			}
			this.surface.append('svg:path').attr('d', svgPathD).attr('fill', 'none').attr('stroke', rightSpritColor).attr('stroke-width', 1).attr('class', this.surfaceAxisRightCls);
			//draw axis label
			i=0;
			var cls, fill;
			while((i++) < 2) {
				cls = (i == 1 ? this.surfaceAxisLeftLabelCls : this.surfaceAxisRightLabelCls);
				fill = (i == 1 ? leftSpritColor : rightSpritColor);
				svgGs = this.surface.selectAll('g.' + cls).data((i == 1 ? axisDatas.left : axisDatas.right)).enter()
				.append('svt:g')
				.attr('class', cls)
				.attr('transform', function(d) {
					if (i == 1) {
						return 'translate('+ (d.x) +','+ (d.ly-2) +')';
					}
				    return 'translate('+ (d.x) +','+ (d.ly-2) +')';
					
				});
				svgGs.append('svg:circle')
					 .attr('cx', (i == 1 ? -6 : 6))
					 .attr('cy', 2)
					 .attr('r', 3)
					 .attr('fill', '#000')
					 .style('display', 'none')
					 .attr('stroke', fill);
				svgGs.append('svg:text')
					 .attr('x', xfn)
					 .attr('y', 5)
					 .text(function(d){ return d.name })
					 .attr('fill', fill)
					 .on('mouseover', function(d, i) {
						 var surface =  me.surface,
						 	gs, dobj;
						 gs = surface.selectAll('g.' + (d.position == 1 ? me.surfaceAxisLeftLabelCls : me.surfaceAxisRightLabelCls));
						 dobj = d3.select(gs[0][i]);
						 dobj.select('circle').style('display', '');
						 dobj.select('text').style('fill', 'green');
						 if (currentSelectScale != d && currentSelectScale != null) {
							 handerFocusLines(currentSelectScale.name, false, false);
						 }
						 handerFocusLines(d.name, true, false);
						 
						 me.updateLegendContent(d);
						 me.showLegend(getXYFromTranslate(dobj.attr('transform')));
						 me.hidePortRelationSprite();
					})
					 .on('mouseout', function(d, i) {
						 var surface =  me.surface,
						 	gs, dobj;
						 gs = surface.selectAll('g.' + (d.position == 1 ? me.surfaceAxisLeftLabelCls : me.surfaceAxisRightLabelCls));
						 dobj = d3.select(gs[0][i]);
						 //dobj.select('circle').style('fill', (d.position == 1 ? '#f0a50a' : '#c20024'));
						 dobj.select('circle').style('display', 'none');
						 dobj.select('text').style('fill', (d.position == 1 ? leftSpritColor : rightSpritColor));
						 if (currentSelectScale != d) {
							 handerFocusLines(d.name, false, false);
							 currentSelectScale = null;
						 }
						 me.hideLegend();
						 me.hidePortRelationSprite();
					 })
					 .on('click', function(d, i) {
						 me.hidePortRelationSprite();
						 currentSelectScale = d;
						 handerFocusLines(d.name, false, true);
					 })
					 .style('cursor', 'pointer')
			}
		},
		//--------------------------------tipButtons-------------------------------------
		showTipButton: function() {
			var me = this,
				tipButtonCfg = this.tipButtonCfg || {},
				box = this.getBBox(),
				tipButtonSprite = this.tipButtonSprite,
				y, tipButtonSpriteDom;
				tipButtonCfg.collapsedBtnCls = tipButtonCfg.collapsedBtnCls || 'tip-cfg-collapsed-btn-cls';
				tipButtonCfg.width = tipButtonCfg.width || 250;
				tipButtonCfg.height = tipButtonCfg.height || 210;
				this.tipButtonCfg = tipButtonCfg;
			if (this.drawStatus == 1) {
				tipButtonSpriteDom = this.tipButtonSprite[0][0];
				//解决覆盖问题
				this.tipButtonSprite.remove();
				this.surface[0][0].appendChild(tipButtonSpriteDom);
			}
			if (!tipButtonSprite) {
				tipButtonSprite = this.tipButtonSprite = this.surface.append('svg:g')
					.on('mouseover', function() {
						//me.showTipButton();
					})
					.on('mouseout', function() {
						//me.hideTipButton();
					});
				tipButtonSprite.settings = this.tipButtonSettings.settings;
				tipButtonSprite.textBtn = tipButtonSprite.append('svg:circle')
					.attr('class', tipButtonCfg.collapsedBtnCls)
					.attr('cx', 25)
					.attr('r', 25)
					.attr('r', 25)
					.style('stroke-width', 1)
					.style('stroke', '#FFFF00')
					.attr('fill', '#FFFF00')
					.style('opacity', 1)
					.attr('cy', (tipButtonCfg.height/2-25))
				
				//tipButtonSprite.textBtn = tipButtonSprite.append('svg:rect')
				tipButtonSprite.append('svg:rect')
					.attr('x', 50)
					.attr('width', tipButtonCfg.width)
					.attr('height', tipButtonCfg.height)
					.attr('fill', '#000')
					.style('stroke-width', 1)
					.style('stroke', 'none')
					.style('opacity', 0.5)
					.style('stroke-opacity', 0)
				
				tipButtonSprite.d3SettingSprite = tipButtonSprite.selectAll('g.btn-settings').data(tipButtonSprite.settings.data).enter()
					.append('svg:g')
					.attr('transform', function(d, i) {
						return 'translate(60, '+ (20 + i*80) +')';
					})
					.attr('class', function(d, i) {return 'btn-settings btn-settings-'+i});
				
				tipButtonSprite.d3SettingSprite.append('svg:rect')
					.attr('x', 5)
					.attr('width', 20)
					.attr('height', 20)
					.attr('fill', function(d, i) {return tipButtonSprite.settings.colors[i]})
					.attr('y', 2)
				tipButtonSprite.d3SettingSprite.append('svg:text')
					.attr('class', 'real-value-cls')
					.text('')
					.attr('x', 15)
					.style('fill', '#FFF')
					.attr('y', 40)
				tipButtonSprite.d3SettingSprite.append('svg:text')
					.attr('class', 'per-value-cls')
					.text('')
					.attr('x', 15)
					.style('fill', '#FFF')
					.attr('y', 70)
				//btn----add
				tipButtonSprite.d3SettingSprite.append('svg:rect')
					.attr('class', 'add-btn-cls')
					.attr('x', 130)
					.attr('y', 30)
					.attr('rx', 2)
					.attr('rx', 2)
					.attr('width', 16)
					.attr('height', 16)
					.style('fill', '#FFF')
					.style('cursor', 'pointer')
					.style('display', function(d, i) {
						return i == 2 ? 'none' : '';
					})
					.on('mouseover', function(d, i) {
						 tipButtonSprite.select('g.btn-settings-' + i).select('rect.add-btn-cls').style('fill', '#FF82AB')
					})
					.on('mouseout', function(d, i) {
						tipButtonSprite.select('g.btn-settings-' + i).select('rect.add-btn-cls').style('fill', '#FFF')
					})
					.on('click', function(d, i) {
						var expression = tipButtonSprite.settings.expression, 
							v = expression[i].lessthan[0];
						v += 1000000;
						expression[i].lessthan[0] = v;
						me.updateTipButtonContext();
					})
					
				tipButtonSprite.d3SettingSprite.append('svg:path')
					.attr('d', 'M130,38L146,38M138,31L138,44')
					.style('stroke', '#000')
					.style('stroke-width', 1.5)
					.style('cursor', 'pointer')
				
				//btn----sub
				tipButtonSprite.d3SettingSprite.append('svg:rect')
					.attr('class', 'sub-btn-cls')
					.attr('x', 160)
					.attr('y', 30)
					.attr('rx', 2)
					.attr('rx', 2)
					.attr('width', 16)
					.attr('height', 16)
					.style('fill', '#FFF')
					.style('cursor', 'pointer')
					.style('display', function(d, i) {
						return i == 2 ? 'none' : '';
					})
					.on('mouseover', function(d, i) {
						 tipButtonSprite.select('g.btn-settings-' + i).select('rect.sub-btn-cls').style('fill', '#FF82AB')
					})
					.on('mouseout', function(d, i) {
						tipButtonSprite.select('g.btn-settings-' + i).select('rect.sub-btn-cls').style('fill', '#FFF')
					})
					.on('click', function(d, i) {
						var expression = tipButtonSprite.settings.expression, 
							v = expression[i].lessthan[0];
						v -= 1000000;
						expression[i].lessthan[0] = v > 0 ? v : 0;
						me.updateTipButtonContext();
					})
				tipButtonSprite.d3SettingSprite.append('svg:path')
					.attr('d', 'M160,38L176,38')
					.style('stroke', '#000')
					.style('stroke-width', 1.5)
					.style('cursor', 'pointer')
					
				//btn----add-- per
				tipButtonSprite.d3SettingSprite.append('svg:rect')
					.attr('class', 'per-add-btn-cls')
					.attr('x', 130)
					.attr('y', 60)
					.attr('rx', 2)
					.attr('rx', 2)
					.attr('width', 16)
					.attr('height', 16)
					.style('fill', '#FFF')
					.style('cursor', 'pointer')
					.style('display', function(d, i) {
						return i == 2 ? 'none' : '';
					})
					.on('mouseover', function(d, i) {
						 tipButtonSprite.select('g.btn-settings-' + i).select('rect.per-add-btn-cls').style('fill', '#FF82AB')
					})
					.on('mouseout', function(d, i) {
						tipButtonSprite.select('g.btn-settings-' + i).select('rect.per-add-btn-cls').style('fill', '#FFF')
					})
					.on('click', function(d, i) {
						var expression = tipButtonSprite.settings.expression, 
							v = expression[i].lessthan[1];
							v = toFix(v + 0.0002, 4) ;
						expression[i].lessthan[1] = v;
						me.updateTipButtonContext();
					})
				tipButtonSprite.d3SettingSprite.append('svg:path')
					.attr('d', 'M130,68L146,68M138,61L138,75')
					.style('stroke', '#000')
					.style('stroke-width', 1.5)
					.style('cursor', 'pointer')
					
				//btn----sub-- per
				tipButtonSprite.d3SettingSprite.append('svg:rect')
					.attr('class', 'per-sub-btn-cls')
					.attr('x', 160)
					.attr('y', 60)
					.attr('rx', 2)
					.attr('rx', 2)
					.attr('width', 16)
					.attr('height', 16)
					.style('fill', '#FFF')
					.style('cursor', 'pointer')
					.style('display', function(d, i) {
						return i == 2 ? 'none' : '';
					})
					.on('mouseover', function(d, i) {
						 tipButtonSprite.select('g.btn-settings-' + i).select('rect.per-sub-btn-cls').style('fill', '#FF82AB')
					})
					.on('mouseout', function(d, i) {
						tipButtonSprite.select('g.btn-settings-' + i).select('rect.per-sub-btn-cls').style('fill', '#FFF')
					})
					.on('click', function(d, i) {
						var expression = tipButtonSprite.settings.expression, 
							v = expression[i].lessthan[1];
							v = toFix(v - 0.0002, 4) ;
						expression[i].lessthan[1] = v > 0 ? v : 0;
						me.updateTipButtonContext();
					});
				tipButtonSprite.d3SettingSprite.append('svg:path')
					.attr('d', 'M160,68L176,68')
					.style('stroke', '#000')
					.style('stroke-width', 1.5)
					.style('cursor', 'pointer');
				
				this.updateTipButtonContext();
			}
			tipButtonSprite.collapsed = false;
			this.updateTipButtonPosition();
			tipButtonSprite.textBtn.style('display', 'none');
		},
		updateTipButtonContext: function() {
			var me=this,
				tipButtonSprite = this.tipButtonSprite,
				j=0;
			while(j++ < 2) {
				tipButtonSprite.select('g.btn-settings-' + (j-1)).select('text.real-value-cls').text('实际流量小于:' + (tipButtonSprite.settings.expression[j-1].lessthan[0]/1000000) + 'm');
				tipButtonSprite.select('g.btn-settings-' + (j-1)).select('text.per-value-cls').text('百分比小于:' + (tipButtonSprite.settings.expression[j-1].lessthan[1]*100) + '%');
			}
			if (this.drawStatus == 1) {
				if (me.tipButtonTaskId) { //清楚旧的
					clearTimeout(me.tipButtonTaskId);
					me.tipButtonTaskId = null;
				}
				me.tipButtonTaskId = setTimeout(function() {
					me.drawLines();
				}, 1000)
			}
		},
		
		hideTipButton: function() {
			this.tipButtonSprite.collapsed = true;
			this.updateTipButtonPosition();
			this.tipButtonSprite.textBtn.style('display', '');
		},
		updateTipButtonPosition: function(pos) {
			var box = this.getBBox(),
				tipButtonCfg = this.tipButtonCfg,
				tipButtonSprite = this.tipButtonSprite,
				pos = pos || [(tipButtonSprite.collapsed ? (box.width -50) : box.width -tipButtonCfg.width-50),  (box.scrollTop - 100 + (box.height/2))];
			tipButtonSprite.attr('transform', 'translate('+ pos[0] +', '+ pos[1] +')');
		},
		//---------------------------port 关联关系图----------------------------------------
		drawPortRelationSprite: function() {
			var me=this,
				portRelationSprite = this.portRelationSprite,
				height = 210,
				topTitleY = 20,
				bottomTitleY = 200,
				drawCmpHeight = 100,
				space = 40,
				axisCount = 1000,
				pathTopD = 'M0,30.5L' + space + ',30.5', pathBottomD = 'M0,'+(30.5 + drawCmpHeight)+'L'+ space +',' + (30.5 + drawCmpHeight),
				drawMorror = {},
				startDragFn = function() {
					drawMorror.dragstatus = true;
					drawMorror.currentX = event.offsetX;
				},
				endDragFn = function() {
					drawMorror.dragstatus = false;
				},
				onMoveFn = function() {
					if (drawMorror.dragstatus !== true) {return;}
					var dddd = portRelationSprite.attr('transform');
					var xy = getXYFromTranslate(portRelationSprite.attr('transform')) || [0, 0],
						box = me.getBBox(), shouldX;
					shouldX = (xy[0] + (event.offsetX-drawMorror.currentX));
					if (Math.abs(shouldX - box.width)> portRelationSprite.realWidth) { //结束
						shouldX = (box.width - portRelationSprite.realWidth);
					} 
					if (shouldX > 0) {shouldX = 0}
					portRelationSprite.attr('transform', 'translate(' + shouldX + ', ' + xy[1] + ')');
					drawMorror.currentX = event.offsetX;
				},
				i, sprtes;
			if (!portRelationSprite) {
				portRelationSprite = this.portRelationSprite = this.surface.append('svg:g').attr('fill', '#FFF');
				portRelationSprite.realWidth = (axisCount + 3) * space;
				portRelationSprite.bodyCmp = portRelationSprite.append('svg:rect')
					.attr('x',0)
					.attr('y', 0)
					.attr('width', portRelationSprite.realWidth)
					.attr('height', height)
					.attr('fill', '#000')
					.style('opacity', 0.7);
				portRelationSprite.topTitleSprite = portRelationSprite.append('svg:text').text('Top Title').attr('y', topTitleY).attr('x', 20);
				portRelationSprite.bottomTitleSprite = portRelationSprite.append('svg:text').text('Bottom Title').attr('y', bottomTitleY).attr('x', 20);
				portRelationSprite.drawCmpSprite = portRelationSprite.append('svg:g').attr('transform', 'translate(0, '+(topTitleY+10)+')');
				//初始化axis
				for (i=0; i<axisCount; i++) {
					pathTopD = pathTopD + 'M'+(space*(i+1))+',30.5L'+ (space*(i+1)) +',20.5M'+ (space*(i+1)) +',30.5L'+ (space*(i+2)) +',30.5';
					pathBottomD = pathBottomD + 'M'+(space*(i+1))+','+(30.5 + drawCmpHeight)+'L'+ (space*(i+1)) +','+(40.5 + drawCmpHeight)+'M'+ (space*(i+1)) +','+(30.5 + drawCmpHeight)+'L'+ (space*(i+2)) +',' + (30.5 + drawCmpHeight);
				}
				portRelationSprite.drawCmpSprite.append('svg:path').attr('d', pathTopD).attr('stroke', '#f0a50a');
				portRelationSprite.drawCmpSprite.append('svg:path').attr('d', pathBottomD).attr('stroke', '#c20024');
				
				portRelationSprite.height = height;
				portRelationSprite.topTitleY = topTitleY;
				portRelationSprite.bottomTitleY = bottomTitleY;
				portRelationSprite.drawCmpHeight = drawCmpHeight;
				portRelationSprite.space = space;
				portRelationSprite.axisCount = axisCount;
			}
			sprtes = [portRelationSprite, portRelationSprite.bodyCmp];
			Ext.each(sprtes, function(v) {
				v.on('mousedown', startDragFn)
				v.on('mouseup', endDragFn)
				v.on('mousemove', onMoveFn);
				v.style('cursor', 'move')
			});
		},
		showPortRelationSprite: function(x) {
			var portRelationSpriteDom,
				box = this.getBBox(),
				portRelationSprite = this.portRelationSprite,
				realPos;
			if (!portRelationSprite) {
				this.drawPortRelationSprite();
				portRelationSprite = this.portRelationSprite;
			}
			if (this.drawStatus == 1) {
				portRelationSpriteDom = portRelationSprite[0][0];
				portRelationSprite.remove();
				this.surface[0][0].appendChild(portRelationSpriteDom);
			}
			realPos = getXYFromTranslate(portRelationSprite.attr('transform'));
			x = x || (!!realPos ? realPos[0] : 0);
			portRelationSprite.attr('transform', 'translate('+ x +', ' + box.scrollTop + ')');
			portRelationSprite.style('display', '');
			
		},
		hidePortRelationSprite: function() {
			if (this.portRelationSprite) {
				this.portRelationSprite.style('display', 'none');
			}
		},
		//绘制端口曲线
		/**
		 * options = {vField, vLabelField, rField, rLableField, topLabelTile, bottomLableTitle, sizeField}
		 */
		loadPortDatas: function(storeDatas, options) {
			var series = this.series,
				portRelationSprite = this.portRelationSprite,
				datas = portRelationSprite.data = {nodes: [], topDatas: [], bottomDatas: [], topCount: 0, bottomCount: 0, topLabelTile: 'T', bottomLableTitle: 'B', allCoordinate: {}},
				i, len = storeDatas.length, record, port, ip, obj, has = {}, pro, axisEs = [],
				pi = Math.PI,
				cos = Math.cos,
				abs = Math.abs,
				sin = Math.sin,
				floor = Math.floor,
				decideLineColor = function(d, i) {
					var rgbs = '#1C86EE';
					if ((fn = series.decidePortLineColor) && Ext.isFunction(fn)) {
						rgbs = fn(d, i);
					}
					return rgbs;
				},
				diagonal = d3.svg.diagonal()
					.source(function(d) {
						var cxy = datas.allCoordinate[d.get(options.vLabelField) + ':' + d.get(options.vField)];
						return {x:cxy[0], y: cxy[1]};})
					.target(function(d) {var cxy = datas.allCoordinate[d.get(options.rLableField) + ':' + d.get(options.rField)];return {x:cxy[0], y: cxy[1]};})
					.projection(function(d, index, _arrayObj) {
						var spoint = _arrayObj[0],
							dpoint = _arrayObj[3],
							sx = spoint.x,
							dx = dpoint.x,
							spos = spoint.y < dpoint.y;
						if (index == 1) {//firt C
							d.x = (sx < dx ? (sx - 30) : (sx + 30));
							d.y = spos ? (d.y + 20) : (d.y - 20);
						}
						if (index == 2) {//TWO C
							d.x = dpoint.x;
							d.y = spos ? (d.y + 10) : (d.y - 10);
						}
						//加入箭头
						if (index == 3) {
							arrowX = 8 * sin(pi/6);
							arrowY = 8 * cos(pi/6);
							arrowL = 'M' + d.x + ',' + d.y + 'L' + (d.x-arrowX) + ',' + (spos ? (d.y-arrowY) : (d.y + arrowY)) + 'M' + d.x + ',' + d.y + 'L' + (d.x+arrowX) + ',' + (spos ? (d.y-arrowY) : (d.y + arrowY));
							return [d.x, d.y + arrowL];
						}
						return [abs(d.x) + 0.5, abs(d.y) + 0.5];
				});
			
			portRelationSprite.drawCmpSprite.selectAll('text.port-axis-top-item-cls').remove();
			portRelationSprite.drawCmpSprite.selectAll('text.port-axis-bottom-item-cls').remove();
			portRelationSprite.drawCmpSprite.selectAll('path.port-lines-item-cls').remove();
			portRelationSprite.drawCmpSprite.selectAll('text.port-lines-item-text-cls').remove();
			
			for (i=0; i<len; i++) {
				record = storeDatas.get(i);
				port = record.get(options.vField);
				ip = record.get(options.vLabelField);
				pro = ip + ':' + port;
				if (!has[pro]) {
					obj = {data: record, port: port, ip: ip, field: options.vField};
					datas.nodes.push(obj);
					if (ip == options.topLabelTile) {
						datas.topDatas.push(obj);
						datas.topCount = datas.topCount + 1;
						obj.pos = 1;
					} else {
						datas.bottomDatas.push(obj);
						datas.bottomCount = datas.bottomCount + 1;
						obj.pos = 2;
					}
					has[pro] = true;
				}
				port = record.get(options.rField);
				ip = record.get(options.rLableField);
				pro = ip + ':' + port;
				if (!has[pro]) {
					obj = {data: record, port: port, ip: ip, field: options.vField};
					datas.nodes.push(obj);
					if (ip == options.topLabelTile) {
						datas.topDatas.push(obj);
						datas.topCount = datas.topCount + 1;
						obj.pos = 1;
					} else {
						datas.bottomDatas.push(obj);
						datas.bottomCount = datas.bottomCount + 1;
						obj.pos = 2;
					}
					has[pro] = true;
				}
			}  
			datas.topLabelTile = options.topLabelTile
			datas.bottomLableTitle = options.bottomLableTitle
			
			//绘制PORT节点
			axisEs.push(portRelationSprite.drawCmpSprite.selectAll('text.port-axis-top-item-cls').data(datas.topDatas).enter())
			axisEs.push(portRelationSprite.drawCmpSprite.selectAll('text.port-axis-bottom-item-cls').data(datas.bottomDatas).enter())
			Ext.each(axisEs, function(v, index) {
				var y = (index == 0 ? (17) : (portRelationSprite.drawCmpHeight+50));
				v.append('svg:text')
				.text(function(d, i) {return d.port})
				.style('fill', (index == 0 ? '#f0a50a' : '#c20024'))
				.attr('class', (index == 0 ? 'port-axis-top-item-cls' : 'port-axis-bottom-item-cls'))
				.attr('x', function(d, i) {
					var x = (i+1)*portRelationSprite.space - (calculateAxisLabelFn(d.port) /2);
					if (d.pos == 1) { //起始点
						datas.allCoordinate[d.ip + ':' + d.port] = [x + (calculateAxisLabelFn(d.port) /2), y + 10];
					} else {
						datas.allCoordinate[d.ip + ':' + d.port] = [x + (calculateAxisLabelFn(d.port) /2), y-20];
					}
					return x
				})
				.attr('y', y);
			})
			portRelationSprite.topTitleSprite.text(datas.topLabelTile)
			portRelationSprite.bottomTitleSprite.text(datas.bottomLableTitle);
			
			//绘制线
			var lineDatas = [];
			for (i=0, len = storeDatas.length; i<len; i++) {
				lineDatas.push(storeDatas.get(i));
			}
			portRelationSprite.drawCmpSprite.selectAll('path.port-lines-item-cls').data(lineDatas).enter()
				.append('svg:path')
				.attr('class', 'port-lines-item-cls')
				.attr('d', diagonal)
				.style('stroke', decideLineColor)
				.style('stroke-width', 1)
				.style('fill', 'none')
				
			portRelationSprite.drawCmpSprite.selectAll('text.port-lines-item-text-cls').data(lineDatas).enter()
				.append('svg:text')
				.attr('class', 'port-lines-item-text-cls')
				.text(function(d, i) {
					return toFix((d.get(options.sizeField) / 1000000), 2) + 'M';
				})
				.style('fill', '#00CD00')
				.style('stroke-rotate', 30)
				.attr('transform', function(d, i) {
					var sxy = datas.allCoordinate[d.get(options.vLabelField) + ':' + d.get(options.vField)],
					    dxy = datas.allCoordinate[d.get(options.rLableField) + ':' + d.get(options.rField)],
					    d = {y: sxy[1]},
						sx = sxy[0],
						dx = dxy[0];
					stop = sxy[1] < dxy[1];
					d.x = (sx < dx ? (sx - 30) : (sx + 30));
					d.y = stop ? (d.y + 25) : (d.y - 25);
					return 'translate('+ (d.x - 40) +', '+ d.y +') rotate(45)';
				})
			this.showPortRelationSprite(1);
		},
		
		onDestroy: function() {
			this.getEl().removeListener('scroll', this.onScrollEvent, this);
			this.callParent(arguments);
		}
	  }
	});	
				

[/align]
  • 大小: 562.8 KB
  • 大小: 450.8 KB
  • 大小: 227.3 KB
  • 大小: 231.7 KB
  • 大小: 564.7 KB
  • 大小: 230.7 KB
  • 大小: 564.7 KB
  • 大小: 453.5 KB
  • 大小: 223.6 KB
分享到:
评论

相关推荐

    精通D3.js:交互式数据可视化高级编程

    交互性是现代数据可视化的关键要素之一,D3.js通过强大的事件处理机制来实现用户交互。当用户与图表进行交互时,如点击、悬停或拖动,D3.js可以捕获这些事件并执行相应的函数,从而动态地改变图表的显示方式。这一...

    d3.js实现知识图谱可视化

    js实现知识图谱可视化,可移植性强,效果良好,我是用在了Django框架下,对于知识图谱查询结果的输出,也可以用在spring框架下。

    数据可视化实战使用D3设计交互式图表.pdf+源码

    本资源是关于“数据可视化实战:使用D3设计交互式图表”的教程,结合了理论知识与实际操作,旨在帮助用户掌握D3.js库在创建交互式数据可视化中的应用。 D3.js,全称Data-Driven Documents,是由Mike Bostock开发的...

    d3-relationshipgraph, 使用d3js可视化父对象关系的框架.zip

    d3-relationshipgraph, 使用d3js可视化父对象关系的框架 d3-relationshipgraph 用于创建 D3.js的父级子关系的框架。示例在这里查看一个工作示例 。如果你已经使用 d3-relationshipgraph,可以编辑这个自述文件并为你...

    D3js使用Web标准实现数据可视化的JavaScript库

    7. **交互性(Interactivity)**: D3.js库支持事件监听和响应,可以创建交互式可视化,如悬停显示详情、点击展开子项等,提升用户的参与度和理解深度。 8. **模块化设计**: D3.js遵循模块化设计,允许开发者按需...

    精通D3.js:交互式数据可视化高级编程1

    《精通D3.js:交互式数据可视化高级编程1》是一本深入探讨D3.js库的指南,旨在帮助读者掌握创建动态、交互式数据可视化的技能。D3.js,全称Data-Driven Documents,是一个强大的JavaScript库,专为数据驱动的Web文档...

    D3.js自学推荐的两本书(精通D3.js交互式数据可视化高级编程,d3.js数据可视化实践)

    这本书旨在帮助读者从初级到高级全面掌握D3.js,特别关注交互式数据可视化的实现。书中涵盖了以下核心知识点: - **D3.js基础知识**:讲解D3.js的核心概念,如选择集、数据绑定、元素的添加与更新、转换和动画。 - ...

    Neo4j+springboot+vue+d3.js知识图谱构建和可视化

    在构建和可视化知识图谱的过程中,我们通常会...以上就是使用Neo4j、SpringBoot、Vue.js和d3.js构建知识图谱及可视化的关键知识点,它们共同作用,形成一个完整的知识图谱系统,能够有效地管理和展示复杂的关系数据。

    D3_d3公司网页_可视化网页设计_

    D3,全称Data-Driven Documents,是一个强大的JavaScript库,专用于数据绑定和操作DOM(Document Object Model)以实现数据可视化。在网页设计中,D3.js提供了一种灵活的方法,将复杂的数据集转换为直观的图表和图形...

    D3可视化史上最全中文文档

    D3.js的核心理念是通过数据绑定(data binding)和数据驱动的DOM操作来实现动态和交互式的可视化。它的强大之处在于灵活性和定制性,开发者可以精确控制每一个SVG元素或HTML节点,从而创建出几乎任何想象得到的数据...

    d3.js第七次人口普查可视化分析(含数据和源代码)

    描述中提到,使用d3.js对数据进行处理并转化为各种图形,如折线图、饼状图和条形图,这些都是常见的数据可视化方式,便于人们直观地理解复杂的信息。这些图形用来展示人口普查中的关键指标,包括受教育程度、年龄...

    基于Neo4j+springboot+vue+d3.js知识图谱构建和可视化

    知识图谱是一种结构化的数据表示方式,用于存储、管理和理解复杂的数据关系。...总的来说,这个项目通过整合各种技术,实现了知识图谱的高效构建和可视化,提供了丰富的交互功能,有助于用户理解和探索复杂的数据关系。

    d3dag用于可视化有向无环图的布局算法

    本文将深入探讨如何使用**d3dag**库来实现DAG的可视化布局算法。 **d3dag**是一个基于**D3.js**(Data-Driven Documents)的JavaScript库,专门设计用于高效地绘制和布局DAG。D3.js是一个强大的JavaScript库,它...

    vue-d3-graph:vue+d3v6实现动态知识图谱可视化展示(包含2D和3D图谱展示)

    博客地址:...由于发现在我的博客通过点击GitHub链接,会跳转到别人盗用的下载地址,而且还是VIP收费,所以自己把代码上传CSDN资源上。 【因为缺分,所以收5个积分,免费可以到Github上下载最新的代码】

    知识图谱可视化,前端 vue.js + d3.js.zip

    知识图谱可视化是一种将复杂数据结构以图形方式展示的技术,帮助用户直观理解数据间的关系和模式。在这个项目中,我们关注的是使用前端技术Vue.js和D3.js来实现这一目标。Vue.js是一款轻量级的JavaScript框架,它以...

    对招聘数据进行爬取、分析、可视化,使用d3可视化.zip

    在这个名为“对招聘数据进行爬取、分析、可视化,使用d3可视化.zip”的项目中,我们涉及了几个关键的IT领域,包括数据爬取、数据分析和数据可视化。这些是现代数据科学的重要组成部分,特别是对于那些想要提升技能的...

    数据可视化d3.js编写

    总结来说,这个“重庆市网吧可视化分析”项目涉及到d3.js库的使用,结合百度地图API获取和展示地理位置信息,通过折线图、饼图和散点图呈现多元数据,并实现交互式功能,以帮助我们洞察重庆市网吧的运营状况。...

    D3.js数据可视化实战手册.pdf

    D3.js数据可视化实战手册.pdf

    数据可视化实现-使用D3设计交互图表

     《图灵程序设计丛书·数据可视化实战:使用D3设计交互式图表》这本书很有意思,而且对读者要求不高。不需要知道什么是数据可视化,也不用有太多Web开发背景就能看懂它。不信?翻一翻就知道这是一本既好玩又实用的...

Global site tag (gtag.js) - Google Analytics