D3.js 个 jQuery 对象的选择器和函数

D3.js selectors and functions on a jQuery object

我在以前创建的 jQuery 对象上使用 D3 selectOR 和函数时遇到问题。

在我的例子中,我得到了一张法国部门的地图,我想通过 select 菜单缩放到特定的部门。当我用 D3 创建和填充菜单时它工作正常。 但是因为我想要在菜单中有一个搜索框(以快速访问一个特定的部门),所以我使用了提供该选项的 select2 jquery 插件。

问题是,当我用 select2 创建菜单,然后用 D3 填充它时,我丢失了以前用 D3 注册的点击处理程序:当我点击菜单时没有任何反应。

这里有一个 JSFiddle 来展示当我完全使用 D3 时它是如何工作的: http://jsfiddle.net/c62uektb/

这里的 select2 对象和不再起作用的函数(只修改了一行): http://jsfiddle.net/z5ygktnw/

相关部分在第43行和第50行之间:

$("#zoomForm").select2();

d3.select('#zoomForm').selectAll("option")
    .data(topojson.feature(data, data.objects.territoire).features)
    .enter().append("option")
    .text(function(d) { return "department n°" + d.properties.code; })
    .on("click", clicked);

我查看了有关 D3 和 jQuery 之间交互的问题和解释,但没有找到解决问题的答案。

D3 和 jQuery 处理事件处理程序的注册 slightly different, which is why your select2 plugin's select options won't trigger event handlers registered via D3's selection.on() method. An easy way around this would be to use jQuery to register clicked 处理程序函数到您的 select 框:

$("#zoomForm").select2()
  .on("select2:select", clicked);  // Register the event handler

另一方面,当用 D3:

填充 select 框时,您可以摆脱注册
d3.select('#zoomForm').selectAll("option")
    .data(topojson.feature(data, data.objects.territoire).features)
    .enter().append("option")
    .text(function(d) { return "department n°" + d.properties.code; })
//  .on("click", clicked);   // Not needed, done using jQuery

最后,您需要调整 clicked() 处理函数,因为它需要访问使用 D3 绑定的数据。由于 jQuery,与 D3 不同,不会将绑定数据传递给此处理程序,而是将事件对象传递给事件对象,因此您需要自己检索数据:

function clicked(evt) {
  // Get the datum bound to the element by D3
  var d = d3.select(evt.params.data.element).datum(); 

  // ...the rest remains untouched. 

看看这个工作示例:

var width = 600, height = 550, active = d3.select(null);

var path = d3.geo.path();

var projection = d3.geo.conicConformal() //focus on France
 .center([2.454071, 47.279229])
 .scale(3000)
 .translate([width / 2, height / 2]);

var zoom = d3.behavior.zoom()
    .translate([0, 0])
    .scale(1)
    .scaleExtent([1, 20])
    .on("zoom", zoomed);
 
path.projection(projection);

var svg = d3.select('#map').append("svg")
 .attr("id", "svg")
 .attr("width", width)
 .attr("height", height);
 
var departments = svg.append("g");

svg.call(zoom);

d3.json('https://gist.githubusercontent.com/PierreVivet/f46c2fe235ec7d7ab2db3dbaa163cc50/raw/f2f3fb092beb94f3a0582a9a82a040fa789028c1/departements.json', function(req, data) {
 data.objects.territoire.geometries.forEach(function (d) {
  d.properties = {};
  d.properties.code = d.code;
 });
 
 departments.selectAll("path")
  .data(topojson.feature(data, data.objects.territoire).features)
  .enter()
  .append("path")
  .attr("d", path)
  .attr('id', function(d) {return "d" + d.properties.code;})
  .style("fill", "white")
  .style("stroke", "black")
  .style("stroke-width", ".2px");
 
 $("#zoomForm").select2()
    .on("select2:select", clicked);  // Register the event handler
  
 d3.select('#zoomForm').selectAll("option")
  .data(topojson.feature(data, data.objects.territoire).features)
  .enter().append("option")
  .text(function(d) { return "department n°" + d.properties.code; })
//  .on("click", clicked);
});

function clicked(evt) {
  // Get the datum bound to the element by D3
  var d = d3.select(evt.params.data.element).datum();  

  var bounds = path.bounds(d),
      dx = bounds[1][0] - bounds[0][0],
      dy = bounds[1][1] - bounds[0][1],
      x = (bounds[0][0] + bounds[1][0]) / 2,
      y = (bounds[0][1] + bounds[1][1]) / 2,
      scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
      translate = [width / 2 - scale * x, height / 2 - scale * y];

  svg.transition()
      .duration(750)
      .call(zoom.translate(translate).scale(scale).event);
}

function zoomed() {
  departments.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>

<script src="https://code.jquery.com/jquery-2.2.3.min.js" integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo=" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/ui/1.11.1/jquery-ui.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.full.min.js"></script>

<body>
  <div>
    <form id="form">
      <fieldset>
        <legend>Zoom on</legend>
          <select id="zoomForm" style="width: 28%">
          </select>
      </fieldset>
    </form> 
    <div id="map"></div>
  </div>
</body>