【问题标题】:Concept Map using D3.JS : straight lines instead of curves使用 D3.JS 的概念图:直线而不是曲线
【发布时间】:2019-08-27 01:30:49
【问题描述】:

http://bl.ocks.org/virtuald/ea7438cb8c6913196d8e

以上是一个示例概念图的链接。在鼠标悬停时突出显示曲线的想法是伟大的和动态的。

是否有任何其他示例,在单击感兴趣的数据以显示其相关属性时,而不是此类曲线,仅突出显示直线(水平和垂直)?

可以修改这张带有曲线的地图,以便只出现一条直线吗???实际上,如果您要显示从 excel 表格或工作表中提取的数据,其中有很多相互链接的列,那么这些 cuves 并不总是合适的。请问如何实施?...谢谢v,非常感谢您提供任何信息或线索。

【问题讨论】:

    标签: dictionary d3.js concept


    【解决方案1】:

    要制作直线而不是曲线,请删除在创建“链接”时使用 d3.svg.diagonal:

    // links
    var link = svg.append('g').attr('class', 'links').selectAll(".link")
        .data(data.links)
      .enter().append('path')
        .attr('class', 'link')
        .attr('id', function(d) { return d.id })
        .attr("d", function(d){
          var y1 = d.outer.y * Math.cos(projectX(d.outer.x)),
              x1 = -d.outer.y * Math.sin(projectX(d.outer.x)),
              y2 = d.inner.y + rect_height/2,
              x2 = d.outer.x > 180 ? d.inner.x : d.inner.x + rect_width;
            return "M" + x1 + "," + y1 + "L" + x2 + "," + y2;
        })
        .attr('stroke', function(d) { return get_color(d.inner.name); })
        .attr('stroke-width', link_width);
    

    运行代码:

    <!DOCTYPE html>
    <head>
    	<meta charset="utf-8">
    	<meta name="name" content="Concept Map" />
    	<meta name="description" content="An abstract mapping for parameters. Works best if first tag is 'unique' among the tracklist, and the second tag applies to multiple tracks"/>
    	<meta name="mintags" content="2" />
    	<meta name="maxtags" content="2" />
    	<title>Jam Cellar 2014-05-06</title>
    
    <style>
    
    svg {
        font: 12px sans-serif;
    }
    
    text {
        pointer-events: none;
    }
    
    .inner_node rect {
        pointer-events: all;
    }
    
    .inner_node rect.highlight {
        stroke: #315B7E;
        stroke-width: 2px;
    }
    
    .outer_node circle {
        fill: #fff;
        stroke: steelblue;
        stroke-width: 1.5px;
        pointer-events: all;
    }
    
    .outer_node circle.highlight
    {
        stroke: #315B7E;
        stroke-width: 2px;
    }
    
    .link {
        fill: none;
    }
    
    </style>	
    </head>
    <body>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script>
    //
    // Generated by the Exaile Playlist Analyzer plugin.
    // (C) 2014 Dustin Spicuzza <dustin@virtualroadside.com>
    //
    // This work is licensed under the Creative Commons Attribution 4.0
    // International License. To view a copy of this license, visit
    // http://creativecommons.org/licenses/by/4.0/.
    //
    // Inspired by http://www.findtheconversation.com/concept-map/
    // Loosely based on http://bl.ocks.org/mbostock/4063550
    //
    
    
    var data = [[120, ["like", "call response", "dramatic intro", "has breaks", "male vocalist", "silly", "swing"]], [150, ["brassy", "like", "calm energy", "female vocalist", "swing", "fun"]], [170, ["calm energy", "instrumental", "swing", "like", "happy"]], [140, ["has breaks", "male vocalist", "swing", "piano", "banjo", "chill"]], [160, ["calm energy", "instrumental", "swing", "like", "interesting"]], [140, ["brassy", "like", "energy", "dramatic intro", "male vocalist", "baseball", "swing"]], [170, ["instrumental", "interesting", "high energy", "like", "swing"]], [140, ["instrumental", "energy", "like", "swing"]], [200, ["instrumental", "brassy", "dramatic intro", "like", "swing"]], [160, ["male vocalist", "brassy", "swing", "like", "my favorites"]], [130, ["like", "interesting", "dramatic intro", "male vocalist", "silly", "swing", "gospel"]], [160, ["like", "long intro", "announcer", "energy", "swing", "female vocalist"]], [170, ["instrumental", "swing", "bass", "like"]], [150, ["like", "interesting", "has breaks", "instrumental", "chunky", "swing", "banjo", "trumpet"]], [170, ["like", "has breaks", "male vocalist", "silly", "swing", "banjo"]], [190, ["instrumental", "banjo", "swing"]], [130, ["instrumental", "brassy", "banjo", "like", "swing"]], [160, ["brassy", "like", "energy", "instrumental", "big band", "jam", "swing"]], [150, ["like", "male vocalist", "live", "swing", "piano", "banjo", "chill"]], [150, ["like", "trick ending", "instrumental", "chunky", "swing", "chill"]], [120, ["brassy", "like", "female vocalist", "swing", "chill", "energy buildup"]], [150, ["brassy", "like", "interesting", "instrumental", "swing", "piano"]], [190, ["brassy", "like", "long intro", "energy", "baseball", "swing", "female vocalist"]], [180, ["calm energy", "female vocalist", "live", "like", "swing"]], [200, ["banjo", "like", "long intro", "interesting", "energy", "my favorites", "male vocalist", "silly", "swing", "fun", "balboa"]], [150, ["brassy", "calm energy", "chunky", "instrumental", "old-timey", "live", "swing"]], [160, ["like", "call response", "interesting", "instrumental", "calm energy", "swing"]], [180, ["interesting", "swing", "fast", "male vocalist"]], [150, ["calm energy", "chunky", "swing", "female vocalist", "like"]], [180, ["like", "has breaks", "male vocalist", "chunky", "silly", "swing"]], [140, ["instrumental", "brassy", "dramatic intro", "swing", "chill"]], [150, ["male vocalist", "trumpet", "like", "swing"]], [150, ["instrumental", "energy", "like", "has breaks", "swing"]], [180, ["brassy", "like", "energy", "has breaks", "instrumental", "has calm", "swing"]], [150, ["female vocalist", "swing"]], [170, ["instrumental", "brassy", "energy", "swing"]], [170, ["calm energy", "instrumental", "energy", "like", "swing"]], [190, ["brassy", "like", "instrumental", "high energy", "swing", "trumpet"]], [160, ["male vocalist", "energy", "swing", "old-timey"]], [170, ["like", "oldies", "my favorites", "fast", "male vocalist", "high energy", "swing"]]];
    
    // transform the data into a useful representation
    // 1 is inner, 2, is outer
    
    // need: inner, outer, links
    //
    // inner: 
    // links: { inner: outer: }
    
    
    var outer = d3.map();
    var inner = [];
    var links = [];
    
    var outerId = [0];
    
    data.forEach(function(d){
    	
    	if (d == null)
    		return;
    	
    	i = { id: 'i' + inner.length, name: d[0], related_links: [] };
    	i.related_nodes = [i.id];
    	inner.push(i);
    	
    	if (!Array.isArray(d[1]))
    		d[1] = [d[1]];
    	
    	d[1].forEach(function(d1){
    		
    		o = outer.get(d1);
    		
    		if (o == null)
    		{
    			o = { name: d1,	id: 'o' + outerId[0], related_links: [] };
    			o.related_nodes = [o.id];
    			outerId[0] = outerId[0] + 1;	
    			
    			outer.set(d1, o);
    		}
    		
    		// create the links
    		l = { id: 'l-' + i.id + '-' + o.id, inner: i, outer: o }
    		links.push(l);
    		
    		// and the relationships
    		i.related_nodes.push(o.id);
    		i.related_links.push(l.id);
    		o.related_nodes.push(i.id);
    		o.related_links.push(l.id);
    	});
    });
    
    data = {
    	inner: inner,
    	outer: outer.values(),
    	links: links
    }
    
    // sort the data -- TODO: have multiple sort options
    outer = data.outer;
    data.outer = Array(outer.length);
    
    
    var i1 = 0;
    var i2 = outer.length - 1;
    
    for (var i = 0; i < data.outer.length; ++i)
    {
    	if (i % 2 == 1)
    		data.outer[i2--] = outer[i];
    	else
    		data.outer[i1++] = outer[i];
    }
    
    console.log(data.outer.reduce(function(a,b) { return a + b.related_links.length; }, 0) / data.outer.length);
    
    
    // from d3 colorbrewer: 
    // This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/).
    var colors = ["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"]
    var color = d3.scale.linear()
        .domain([60, 220])
        .range([colors.length-1, 0])
        .clamp(true);
    
    var diameter = 960;
    var rect_width = 40;
    var rect_height = 14;
    
    var link_width = "1px"; 
    
    var il = data.inner.length;
    var ol = data.outer.length;
    
    var inner_y = d3.scale.linear()
        .domain([0, il])
        .range([-(il * rect_height)/2, (il * rect_height)/2]);
    
    mid = (data.outer.length/2.0)
    var outer_x = d3.scale.linear()
        .domain([0, mid, mid, data.outer.length])
        .range([15, 170, 190 ,355]);
    
    var outer_y = d3.scale.linear()
        .domain([0, data.outer.length])
        .range([0, diameter / 2 - 120]);
    
    
    // setup positioning
    data.outer = data.outer.map(function(d, i) { 
        d.x = outer_x(i);
        d.y = diameter/3;
        return d;
    });
    
    data.inner = data.inner.map(function(d, i) { 
        d.x = -(rect_width / 2);
        d.y = inner_y(i);
        return d;
    });
    
    
    function get_color(name)
    {
        var c = Math.round(color(name));
        if (isNaN(c))
            return '#dddddd';	// fallback color
        
        return colors[c];
    }
    
    // Can't just use d3.svg.diagonal because one edge is in normal space, the
    // other edge is in radial space. Since we can't just ask d3 to do projection
    // of a single point, do it ourselves the same way d3 would do it.  
    
    
    function projectX(x)
    {
        return ((x - 90) / 180 * Math.PI) - (Math.PI/2);
    }
    
    var svg = d3.select("body").append("svg")
        .attr("width", diameter)
        .attr("height", diameter)
      .append("g")
        .attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
        
    
    // links
    var link = svg.append('g').attr('class', 'links').selectAll(".link")
        .data(data.links)
      .enter().append('path')
        .attr('class', 'link')
        .attr('id', function(d) { return d.id })
        .attr("d", function(d){
          var y1 = d.outer.y * Math.cos(projectX(d.outer.x)),
              x1 = -d.outer.y * Math.sin(projectX(d.outer.x)),
              y2 = d.inner.y + rect_height/2,
              x2 = d.outer.x > 180 ? d.inner.x : d.inner.x + rect_width;
            return "M" + x1 + "," + y1 + "L" + x2 + "," + y2;
        })
        .attr('stroke', function(d) { return get_color(d.inner.name); })
        .attr('stroke-width', link_width);
    
    // outer nodes
    
    var onode = svg.append('g').selectAll(".outer_node")
        .data(data.outer)
      .enter().append("g")
        .attr("class", "outer_node")
        .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")"; })
        .on("mouseover", mouseover)
        .on("mouseout", mouseout);
      
    onode.append("circle")
        .attr('id', function(d) { return d.id })
        .attr("r", 4.5);
      
    onode.append("circle")
        .attr('r', 20)
        .attr('visibility', 'hidden');
      
    onode.append("text")
    	.attr('id', function(d) { return d.id + '-txt'; })
        .attr("dy", ".31em")
        .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
        .attr("transform", function(d) { return d.x < 180 ? "translate(8)" : "rotate(180)translate(-8)"; })
        .text(function(d) { return d.name; });
      
    // inner nodes
      
    var inode = svg.append('g').selectAll(".inner_node")
        .data(data.inner)
      .enter().append("g")
        .attr("class", "inner_node")
        .attr("transform", function(d, i) { return "translate(" + d.x + "," + d.y + ")"})
        .on("mouseover", mouseover)
        .on("mouseout", mouseout);
      
    inode.append('rect')
        .attr('width', rect_width)
        .attr('height', rect_height)
        .attr('id', function(d) { return d.id; })
        .attr('fill', function(d) { return get_color(d.name); });
      
    inode.append("text")
    	.attr('id', function(d) { return d.id + '-txt'; })
        .attr('text-anchor', 'middle')
        .attr("transform", "translate(" + rect_width/2 + ", " + rect_height * .75 + ")")
        .text(function(d) { return d.name; });
    
    // need to specify x/y/etc
    
    d3.select(self.frameElement).style("height", diameter - 150 + "px");
    
    function mouseover(d)
    {
    	// bring to front
    	d3.selectAll('.links .link').sort(function(a, b){ return d.related_links.indexOf(a.id); });	
    	
        for (var i = 0; i < d.related_nodes.length; i++)
        {
            d3.select('#' + d.related_nodes[i]).classed('highlight', true);
            d3.select('#' + d.related_nodes[i] + '-txt').attr("font-weight", 'bold');
        }
        
        for (var i = 0; i < d.related_links.length; i++)
            d3.select('#' + d.related_links[i]).attr('stroke-width', '5px');
    }
    
    function mouseout(d)
    {   	
        for (var i = 0; i < d.related_nodes.length; i++)
        {
            d3.select('#' + d.related_nodes[i]).classed('highlight', false);
            d3.select('#' + d.related_nodes[i] + '-txt').attr("font-weight", 'normal');
        }
        
        for (var i = 0; i < d.related_links.length; i++)
            d3.select('#' + d.related_links[i]).attr('stroke-width', link_width);
    }
    
    </script>

    【讨论】:

      【解决方案2】:

      这就是我正在使用的代码中的完成方式。

          $('path.link').each(function (ind, path) {
              let curveTo = $(path).attr('d'),
                  lineTo = curveTo.replace(/C/, 'L');
              $(path).attr('d', lineTo);
          })
      

      您必须事先为所有 path 元素赋予 .link 类。

                theDiagonal = d3.svg.diagonal()
                ehv.selectAll('.links')
                  .data(allLinks)
                  .enter()
                  .append('g')
                  .append('path')
                  .attr({
                      'class': 'link', //Like this.
                      'd': theDiagonal
                  });
      

      CSS

      path.link, path.drawing-path {
          stroke-dasharray: 3, 1;
          fill: none;
          stroke: gray;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-27
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多