Functions and classes

I have been working with ex6 classes and inheritance. I’ve been trying to use parent functions as interfaces. I am finding that the program behaves differently when I use a function in a non class structure then within class structure, even though it’s exactly the same method and javascript logs it as a function in both cases.

The bellow code segments is where I am having the problem. I am comparing the file <D3.js. implementation to to <BookingsChart.js, D3Chart.js> parent child implementation.
the issue is with <y()> as in this.y = d3.scaleLinear().range([this.height, 0]);
in one instance it works fine and on the other instance (using classes) it sees it as the same method but throws error “d3.v6.min.js:2 Error: attribute y: Expected length, “NaN”.”

index.js

import { bookingsChart } from ‘./D3.js’; //works OK
import BookingsChart from ‘./BookingsChart.js’; //Error attribute y: Expected length, “NaN”.
const bookingsChart = new BookingsChart(pureData, “bookings-chart”);
const callHistoryChart = new CallHistoryChart(pureData, “call-history-chart”);

bookingsChart(pureData);	// OK

bookingsChart.plotChart("Rooms", "Bookings / 10 days");	//FAILS

_____________________________________________________________________________________

BookingsChart.js
import { D3Chart } from './D3Chart.js';

export default class BookingsChart extends D3Chart {
    constructor(data, svgDevId) {
        super(data, svgDevId, 'booking');
    }

    plotChart(xLabel, yLabel) {
        
        this.plotBarChart(this.data, this.xAxis, this.yAxis, this.getX, 
            this.getY.bind(this), xLabel, yLabel, this.ticks, this.margin, this.width, this.height);
    }
}
_____________________________________________________________________________________
D3.js
function plotChart(svg, data) {
	svg.selectAll("bar")
        .data(data)
        .enter().append("rect")
        .style("fill", "steelblue")
        .attr("x", function(d) { return x(d.roomName); })
        .attr("width", x.bandwidth() - 4)
        .attr("y", function(d) { console.log("y(d.booking.sum) ",y(d.booking.sum)); return y(d.booking.sum); })	// y() Works OK
        .attr("height", function(d) { return height - y(d.booking.sum); })
        .on("mouseover", function(m, d) {
            d3.select(this).style("fill", "orange")
            return tooltip.style("visibility", "visible")
                .style("left", m.clientX + "px")             
                .style("top", (y(d.booking.sum) + 100) + "px")
                .style("opacity", ".85")
                .html(toolTipHtml(d));
            })
        .on("mouseout", function(){
            d3.select(this).style("fill", "steelblue")
            return tooltip.style("visibility", "hidden");
        })
        .on("click", (m, d) => {
            window.open(`http://${d.ipV4}`);
        })

_____________________________________________________________________________________
D3Chart.js
export class D3Chart {
constructor(data, svgDevId, source="booking") {
	.
	.
	.
	this.x = d3.scaleBand(d3.schemeCategory10).range([0, this.width], .05).padding(.05);
	this.y = d3.scaleLinear().range([this.height, 0]);

	this.getYValuesCB = function(rec) {		
		return rec.booking.sum;
	}    
	
	svg.selectAll("bar")
            .data(data)
            .enter().append("rect")
            .style("fill", "steelblue")
            .attr("x", function(d) { console.log("d.roomName: ", d.roomName); return x(d.roomName); })
            .attr("width", x.bandwidth() - 4)
            .attr("y", d => { console.log("d.booking.sum ",this.getYValuesCB(d)); return y(this.getYValuesCB(d)); })	//y() throws ERROR "d3.v6.min.js:2 Error: <rect> attribute y: Expected length, "NaN"."
            .attr("height", function(d) { return height - y(d.booking.sum); })
            .on("mouseover", function(m, d) {
                d3.select(this).style("fill", "orange")
                return tooltip.style("visibility", "visible")
                    .style("left", m.clientX + "px")             
                    .style("top", (y(d.booking.sum) + 100) + "px")
                    .style("opacity", ".85")
                    .html(toolTipHtml(d));
                })
            .on("mouseout", function(){
                d3.select(this).style("fill", "steelblue")
                return tooltip.style("visibility", "hidden");
            })
            .on("click", (m, d) => {
                window.open(`http://${d.ipV4}`);
            })
	
}

Would seem to imply that this.getYValuesCB is returning something that doesnt have a length.
What’s your console show for the logging of that line?

Hi, thank you for the suggestion. However, getYValuesCB() returns an integer value.
I tried putting a row value in the y() but throws same error

Does it return an integer value in all cases?
Without seeing your data, it’s difficult to say, but i’d guess that one of your bars is failing to get a Y value.

You should be seeing a (well, 2 actually) console output for each bar in the set when you run this…

.attr("y", d => { console.log("d.booking.sum ",this.getYValuesCB(d)); return y(this.getYValuesCB(d)); })
for this line it throws the error for every bar while all values logged were integers

Just a quick thought but is it a binding issue with this. You are using an arrow function there, which doesn’t have it’s own ‘this’ property. Instead this will be lexically scoped.

What happens if you use a standard function instead?

.attr("y", function(d) {
    const value = this.getYValuesCB(d))
    console.log("d.booking.sum ", value)
    return value
})
1 Like