1

I am switching a reusable D3 v5 chart over to use ES6 classes and am having trouble implementing functions that update variables like a zoom function. So far I have a working map:

class myMap{
  constructor(args = {}){

    this.data = args.data;
    this.topo = args.topo;
    this.element =document.querySelector(args.element);
    this.width =args.width || this.element.offsetWidth;
    this.height = args.height || this.width / 2;


    this.setup();
 }

setup(){
this.projection = d3.geoMercator()
                         .translate([(this.width/2), (this.height/2)])
                         .scale( this.width / 2 / Math.PI);

this.path = d3.geoPath().projection(this.projection);

   // zoom fuction inserted here
  this.element.innerHTML ='';
    this.svg =d3.select(this.element).append("svg")
                 .attr("width", this.width)
                 .attr("height", this.height)
                 //.call(zoom)
                 .append("g");

  this.plot = this.svg.append("g");  
   d3.json(this.topo).then( world => {

    var topo = topojson.feature(world, world.objects.countries).features;

    this.draw(topo);
    });

   }


draw(topo){

var country = this.plot.selectAll(".country")
                 .data(topo);

  country.enter().insert("path")
      .attr("class", "country")
      .attr("d", this.path)
      .attr('id', 'countries')
      .attr("fill", #cde)
      .attr("class", "feature");

  }
 //move(){} goes here  

}

which is called using:

const chart = new myMap({
  element: '#map',
    data: DATA_IN_JSON,
    topo:"../../../LINK_to_topojsonfile"});

When using functions I added zooming by using a variable and calling the move function, with a .call(zoom) appended to the SVG:

var zoom = d3.zoom()
    .scaleExtent([1, 9])
    .on("zoom", move);

function move() {
  g.style("stroke-width", 1.5 / d3.event.transform.k + "px");
  g.attr("transform", d3.event.transform);
}

Using the classes I tried declaring zoom in the setup() part of the class and calling move form .on("zoom", this.move) and attaching a call function to the SVG as marked in comments above. but I get a Uncaught TypeError: Cannot read property 'style' of undefined at SVGSVGElement.move in the move function when referencing this.plot

const zoom = d3.zoom()
               .scaleExtent([1, 9])
               .on("zoom", this.move);

 move() {
   this.plot
       .style("stroke-width", 1.5 / d3.event.transform.k + "px");
   this.plot
       .attr("transform", d3.event.transform);
 }
ccsv
  • 8,188
  • 12
  • 53
  • 97
  • Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – altocumulus Oct 09 '18 at 10:25
  • 1
    @altocumulus nope not really this is asking a specific case of using the .bind(this) to access an event handler inside a class not inside a function which is the case you listed as a duplicate. – ccsv Oct 09 '18 at 10:33
  • You are right, my bad! I wanted to have this closed as duplicate of ["es6 Javascript class using this inside a callback \[duplicate\]"](/q/36498029) which is the same for class methods. That question is marked as duplicate of the one I mistakenly refered to first. Nonetheless, the same principles apply as JS classes are merely the often quoted syntactic sugar for the underlying prototypal language. – altocumulus Oct 09 '18 at 10:54
  • @altocumulus I agree the concepts are the same but I would never be able to find an answer to my case by just by searching SO. – ccsv Oct 09 '18 at 11:32
  • 1
    That's why duplicate questions—as long as they are good quality—are neither deleted nor considered bad; they are just different entry points to the same problem. I had already started writing my own answer expanding on rioV8's post when I figured that this topic must have been covered multiple times before, which, as it turned out, it has been. Both questions linked to in my previous comments explain very well the three solutions that come mind. – altocumulus Oct 09 '18 at 11:41

1 Answers1

0

you need to bind this

const zoom = d3.zoom()
    .scaleExtent([1, 9])
    .on("zoom", this.move.bind(this));

console.log the this inside the move()

rioV8
  • 24,506
  • 3
  • 32
  • 49
  • Ok that worked. So now I have to figure out what the bind(this) part does. Thanks not sure why you got down voted – ccsv Oct 09 '18 at 09:08