Alan
Alan

Reputation: 362

d3 circle .on("click") event not firing

I understand it should be as simple as selecting the element you need and applying the call to it, but in my case, nothing is happening when I do so.

In my case, I need to re draw circles based on a zoom level of a map.

If the zoom level is < a certain number, use dataset A for the circles. If the zoom level is > the number use dataset B to draw the circles.

I can draw the circles fine, and they do change on changing of the zoom level, but when I add an .on("click") event to these though, nothing happens.

Here is a Codepen link showing the lack of click event working CODEPEN LINK

Here is the code I am using, I have a feeling I am doing something wrong in the update() function, and the way I am using the .remove() function:

L.mapbox.accessToken = 'pk.eyJ1Ijoic3RlbmluamEiLCJhIjoiSjg5eTMtcyJ9.g_O2emQF6X9RV69ibEsaIw';
var map = L.mapbox.map('map', 'mapbox.streets')
  .setView([53.4072, -2.9821], 14);

var data = {
  "largeRadius": [{
    "coords": [53.3942, -2.9785],
    "name": "Jamaica Street"
  }, {
    "coords": [53.4073, -2.9824],
    "name": "Hood Street"
  }],
  "smallRadius": [{
    "coords": [53.4075, -2.9936],
    "name": "Chapel Street"
  }, {
    "coords": [53.4073, -2.9824],
    "name": "Hood Street"
  }]
};

// Sort data for leaflet LatLng conversion
data.largeRadius.forEach(function(d) {
  d.LatLng = new L.LatLng(d.coords[0], d.coords[1]);
});
data.smallRadius.forEach(function(d) {
  d.LatLng = new L.LatLng(d.coords[0], d.coords[1]);
});

var svg = d3.select(map.getPanes().overlayPane).append("svg");

var g = svg.append("g").attr("class", "leaflet-zoom-hide");

var circles = g.selectAll("circle")
  .data(data.smallRadius)
  .enter().append("circle");

function update() {
  circles.remove();
  translateSVG();

  var dataInstance;
  var radius;

  if (map.getZoom() < 17) {
    dataInstance = data.largeRadius;
    radius = 0.008;
  } else {
    dataInstance = data.smallRadius;
    radius = 0.001;
  }

  dataInstance.forEach(function(d) {
    d.LatLng = new L.LatLng(d.coords[0], d.coords[1]);
  });

  circles = g.selectAll("circle")
    .data(dataInstance)
    .enter().append("circle")
    .attr("id", function(d) {
      return d.name
    })
    .attr("cx", function(d) {
      return map.latLngToLayerPoint(d.LatLng).x
    })
    .attr("cy", function(d) {
      return map.latLngToLayerPoint(d.LatLng).y
    })
    .attr("r", function() {
      return radius * Math.pow(2, map.getZoom())
    });
}

function translateSVG() {
  var width = window.innerWidth;
  var height = window.innerHeight;

  var regExp = /\(([^)]+)\)/;
  var translateString = regExp.exec(document.querySelector(".leaflet-map-pane").attributes[1].nodeValue);
  var translateX = parseInt(translateString[1].split(" ")[0]);
  var translateY = parseInt(translateString[1].split(" ")[1]);

  if (translateX < 0) {
    translateX = Math.abs(translateX);
  } else {
    translateX = -translateX;
  }
  if (translateY < 0) {
    translateY = Math.abs(translateY);
  } else {
    translateY = -translateY;
  }

  svg.attr("width", width);
  svg.attr("height", height);
  svg.attr("viewBox", function() {
    return translateX + " " + translateY + " " + width + " " + height;
  });
  svg.attr("style", function() {
    return "transform: translate3d(" + translateX + "px, " + translateY + "px, 0px);";
  });
}

// THIS IS THE CLICK EVENT THAT DOES NOT WORK
circles.on("click", function () {
  alert("clicked");
})

map.on("moveend", update);
update();

Upvotes: 1

Views: 3443

Answers (1)

Wakeuphate
Wakeuphate

Reputation: 503

I'm not sure if this fixes your issue completely, mostly because I'm not sure I fully understand what you're trying to achieve, but if you move the 'click' code:

circles.on("click", function () {
  alert("clicked");
});

Inside your update, then you'll rebind that after you've done the destroy and re-create, so your update function becomes this:

function update() {
  circles.remove();
  translateSVG();

  var dataInstance;
  var radius;

  if (map.getZoom() < 17) {
    dataInstance = data.largeRadius;
    radius = 0.008;
  } else {
    dataInstance = data.smallRadius;
    radius = 0.001;
  }

  dataInstance.forEach(function(d) {
    d.LatLng = new L.LatLng(d.coords[0], d.coords[1]);
  });

  circles = g.selectAll("circle")
    .data(dataInstance)
    .enter().append("circle")
    .attr("id", function(d) {
      return d.name
    })
    .attr("cx", function(d) {
      return map.latLngToLayerPoint(d.LatLng).x
    })
    .attr("cy", function(d) {
      return map.latLngToLayerPoint(d.LatLng).y
    })
    .attr("r", function() {
      return radius * Math.pow(2, map.getZoom())
    });

    circles.on("click", function () {
      alert("clicked");
    });
}

and you then remove the circles.on("click") part from the bottom. It may also be worth making sure you're releasing that bind each time, i'm unsure if it'll be overwriting the memory or adding to it each update.

Here's a fork of yours where it seems to be working as I imagine it: http://codepen.io/anon/pen/waqJqB?editors=101

Upvotes: 1

Related Questions