如何将CSV文件中的链接添加到使用D3生成的SVG元素?

时间:2014-06-29 21:50:12

标签: javascript html csv svg d3.js

我有点绑定,需要帮助我将svg元素与CSV文件中包含的URL相关联。我有一个超过100个符号的符号图。符号基于CSV文件中从经度和纬度中提取的坐标,该文件还包含我希望每个唯一符号链接到的链接。我知道有一种简单的方法可以做到这一点,很确定我忽视了解决方案。

我的CSV文件如下:

        name,longitude,latitude,city,state,url

查尔斯顿学院,803,342,查尔斯顿,SC,http://sitename.com/colleges/college-of-charleston/

等...

我的符号是使用D3生成的,并放在我的SVG地图上。我也使用D3将符号包装在锚标签中。我只是想让这些锚标签链接到与该特定符号的纬度和经度相关的相应网址。

  /* Start SVG */
    var width = 960,
        height = 640.4,
        positions = [],
        centered;

    var bodyNode = d3.select('#Map').node();
    var list = $('.school-list').each(function(i){});
    var svg = d3.select("#Map");
    var contain = d3.select("#map-contain");
    var circles = svg.append("svg:g")
                     .attr("id", "circles");
    var g = d3.selectAll("g");

        // var locationBySchools = {};

        d3.csv("http://sitename.com/wp-content/themes/vibe/homepage/schools.csv",function(schools){
            schools = schools.filter(function(schools){
            var location = [+schools.longitude, +schools.latitude];
            // locationBySchools[schools.loc] = location;
            positions.push(location);
            return true;
        });



            circles.selectAll("circles")
            .data(schools)
            .enter().append("svg:a")
            .attr("xlink:href", function(d) { })
            .append("svg:circle")
            .attr("cx", function(d,i) {return positions[i][0]})
            .attr("cy", function(d,i) {return positions[i][1]})
            .attr("r", function(d,i) {return 6})
            .attr("i", function(d,i) {return i})
            .attr("class", "symbol")

真的坚持这个......有什么想法吗?

1 个答案:

答案 0 :(得分:5)

简短的回答是,在分配url属性时,您应该只是从数据中返回xlink:href属性:

.attr("xlink:href", function(d) { return d.url; }) 

但是,您发布的代码还有其他一些问题。

问题1. circles.selectAll('circles')

首先选择g元素,然后在其中选择标记名为circles的所有元素。问题是circles不是有效的svg标记。这只是创建一个空选择,在这种情况下可以,因为选择仅用于创建新元素。但是,做这样的虚拟选择是一个坏习惯,对于试图理解你的代码的其他人来说,这可能会让人感到困惑。相反,您应该决定要给每个新链接元素的类名,并使用该类名进行选择。例如,如果您决定为其提供link类,则需要执行以下操作:

首先使用class="link"创建所有元素的选择:

circles.selectAll('.link')

此选择最初为空,但是当您使用.data()将数据绑定到它时,将为其提供一个输入选择,您可以使用它来创建新元素。然后,您可以将link类添加到新创建的元素中:

.data(schools).enter().append('svg:a')
  .attr('class', 'link')

问题2. .attr("i", function(d,i) {return i})

这个很简单,svg元素上没有i这样的属性。如果要在元素上存储任意数据以便以后可以访问它,可以使用data attribute。在这种情况下,您可能希望使用像data-index这样的好的和语义的东西。

问题3. positions.push(location)

这是一个很大的问题。我不建议您创建一个单独的数组来存储数据集中更改的值。您可以在d3.csv()函数调用中使用accessor function,并以这种方式清理传入的数据。它将使您不必在两个独立的阵列中维护一致的数据。访问器函数将迭代数据集,将当前数据作为输入,并应返回表示将使用的调整数据的对象。这是使用一元操作员强制经度和经度的好地方:

function accessor(d) {
  return {
    name: d.name,
    longitude: +d.longitude,
    latitude: +d.latitude,
    city: d.city,
    state: d.state,
    url: d.url
  };
}

将访问者功能挂钩到d3.csv()通话中有两种不同的方法:

方法1:将中间参数添加到d3.csv(),以便参数为(<url>, <accessor>, <callback>)

d3.csv('path/to/schools.csv', accessor, function(schools) {
  // ...etc...
});

方法2:使用.row()

d3.csv()方法
d3.csv('path/to/schools.csv')
  .row(accessor)
  .get(function(schools) {
     // ...etc...
  });

现在,当您想要以首选格式访问纬度和经度时,可以从绑定数据中获取它们,而不是从外部源获取。这可以保持一切清洁和一致。


将所有这些放在一起,你会得到以下结果:

d3.csv('http://sitename.com/wp-content/themes/vibe/homepage/schools.csv')
  // provide the accessor function
  .row(function accessor(d) {
    return {
      name: d.name,
      longitude: +d.longitude,
      latitude: +d.latitude,
      city: d.city,
      state: d.state,
      url: d.url
    };
   })
  // provide a callback function
  .get(function callback(schools) {
    circles.selectAll('.link')
      .data(schools)
      .enter().append('svg:a')
        .attr('class', 'link')
        // point the link to the url from the data
        .attr('xlink:href', function(d) { return d.url; })
          .append('svg:circle')
            .attr('class', 'symbol')
            // now we can just use longitude and latitude
            //  since we cleaned them up in the accessor fn
            .attr('cx', function(d) { return d.longitude; })
            .attr('cy', function(d) { return d.latitude; })
            // constants can be assigned directly
            .attr('r', 6)
            .attr('data-index', function(d,i) { return i; });
  });