- 浏览: 12821 次
- 性别:
- 来自: 安徽
文章分类
最新评论
图片:
[align=left]
[/align]
[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]
发表评论
-
angular2-download
2016-12-06 10:08 294import { Injectable } from '@an ... -
基于cleditor扩展实现表单设计器(正在实现中...)
2015-02-09 13:47 904计划待写中.... 主体代码已经写好 第三阶段 ... -
easyui form小工具
2015-01-09 15:22 477http://download.microsoft.c ... -
基于elasticsearch Rest URL模板动态生成(索引按照日期切分)
2014-09-18 10:18 2656例如, 日期: 2014-09-11至2014-09-12 T ... -
Ext drag 那些事
2014-08-21 09:30 1327//panel初始化拖拽函数 initDraggable : ... -
javascript基础: Array
2014-05-14 18:01 316Ext4+的文档中列出了所有javascript:Array的 ...
相关推荐
交互性是现代数据可视化的关键要素之一,D3.js通过强大的事件处理机制来实现用户交互。当用户与图表进行交互时,如点击、悬停或拖动,D3.js可以捕获这些事件并执行相应的函数,从而动态地改变图表的显示方式。这一...
js实现知识图谱可视化,可移植性强,效果良好,我是用在了Django框架下,对于知识图谱查询结果的输出,也可以用在spring框架下。
本资源是关于“数据可视化实战:使用D3设计交互式图表”的教程,结合了理论知识与实际操作,旨在帮助用户掌握D3.js库在创建交互式数据可视化中的应用。 D3.js,全称Data-Driven Documents,是由Mike Bostock开发的...
d3-relationshipgraph, 使用d3js可视化父对象关系的框架 d3-relationshipgraph 用于创建 D3.js的父级子关系的框架。示例在这里查看一个工作示例 。如果你已经使用 d3-relationshipgraph,可以编辑这个自述文件并为你...
7. **交互性(Interactivity)**: D3.js库支持事件监听和响应,可以创建交互式可视化,如悬停显示详情、点击展开子项等,提升用户的参与度和理解深度。 8. **模块化设计**: D3.js遵循模块化设计,允许开发者按需...
《精通D3.js:交互式数据可视化高级编程1》是一本深入探讨D3.js库的指南,旨在帮助读者掌握创建动态、交互式数据可视化的技能。D3.js,全称Data-Driven Documents,是一个强大的JavaScript库,专为数据驱动的Web文档...
这本书旨在帮助读者从初级到高级全面掌握D3.js,特别关注交互式数据可视化的实现。书中涵盖了以下核心知识点: - **D3.js基础知识**:讲解D3.js的核心概念,如选择集、数据绑定、元素的添加与更新、转换和动画。 - ...
在构建和可视化知识图谱的过程中,我们通常会...以上就是使用Neo4j、SpringBoot、Vue.js和d3.js构建知识图谱及可视化的关键知识点,它们共同作用,形成一个完整的知识图谱系统,能够有效地管理和展示复杂的关系数据。
D3,全称Data-Driven Documents,是一个强大的JavaScript库,专用于数据绑定和操作DOM(Document Object Model)以实现数据可视化。在网页设计中,D3.js提供了一种灵活的方法,将复杂的数据集转换为直观的图表和图形...
D3.js的核心理念是通过数据绑定(data binding)和数据驱动的DOM操作来实现动态和交互式的可视化。它的强大之处在于灵活性和定制性,开发者可以精确控制每一个SVG元素或HTML节点,从而创建出几乎任何想象得到的数据...
描述中提到,使用d3.js对数据进行处理并转化为各种图形,如折线图、饼状图和条形图,这些都是常见的数据可视化方式,便于人们直观地理解复杂的信息。这些图形用来展示人口普查中的关键指标,包括受教育程度、年龄...
知识图谱是一种结构化的数据表示方式,用于存储、管理和理解复杂的数据关系。...总的来说,这个项目通过整合各种技术,实现了知识图谱的高效构建和可视化,提供了丰富的交互功能,有助于用户理解和探索复杂的数据关系。
本文将深入探讨如何使用**d3dag**库来实现DAG的可视化布局算法。 **d3dag**是一个基于**D3.js**(Data-Driven Documents)的JavaScript库,专门设计用于高效地绘制和布局DAG。D3.js是一个强大的JavaScript库,它...
博客地址:...由于发现在我的博客通过点击GitHub链接,会跳转到别人盗用的下载地址,而且还是VIP收费,所以自己把代码上传CSDN资源上。 【因为缺分,所以收5个积分,免费可以到Github上下载最新的代码】
知识图谱可视化是一种将复杂数据结构以图形方式展示的技术,帮助用户直观理解数据间的关系和模式。在这个项目中,我们关注的是使用前端技术Vue.js和D3.js来实现这一目标。Vue.js是一款轻量级的JavaScript框架,它以...
在这个名为“对招聘数据进行爬取、分析、可视化,使用d3可视化.zip”的项目中,我们涉及了几个关键的IT领域,包括数据爬取、数据分析和数据可视化。这些是现代数据科学的重要组成部分,特别是对于那些想要提升技能的...
总结来说,这个“重庆市网吧可视化分析”项目涉及到d3.js库的使用,结合百度地图API获取和展示地理位置信息,通过折线图、饼图和散点图呈现多元数据,并实现交互式功能,以帮助我们洞察重庆市网吧的运营状况。...
D3.js数据可视化实战手册.pdf
《图灵程序设计丛书·数据可视化实战:使用D3设计交互式图表》这本书很有意思,而且对读者要求不高。不需要知道什么是数据可视化,也不用有太多Web开发背景就能看懂它。不信?翻一翻就知道这是一本既好玩又实用的...