0

My web app is generating an "Invalid Array Width" error at line 462 of Crossfilter.js v1.3.12. This error seems to tell me I have >32 dimensions. The puzzle is that I am not knowingly declaring a new dimension when the error occurs.

I have 10 slider bars, which act as numeric filters on my dataset. At the end of a drag event on the second slider bar, a dimension is declared if none already exists at the second location within the numericDims array. (Edit: even when I declare all the 10 dimensions in advance, and remove the dynamic declaration, the problem still occurs.) About 10 dimensions already exist in the app for other graphics & filters.

The first time I move a slider handle, "new dimension" is logged. After that, every time I move a handle on the same slider, "new dimension" is not logged. This is expected behaviour. But if I move the handles enough times, I get the "Invalid Array Width" error. So, I think I must be accidentally declaring a new dimension every time I move a handle. Can anyone see how I am unwittingly declaring a new dimension? The most relevant code:

  if (!numericDims[tempIndex]) {
    console.log('new dimension');
    numericDims[tempIndex] = facts.dimension(function(p){ return p[d]; }); 
  }


  if (flag==0) {
    prt.classed("activeFilter",true);
    numericDims[tempIndex].filterFunction(function(p){ return p>=min && p<=max; });

  } else {
    prt.classed("activeFilter",false);
    numericDims[tempIndex].filterAll();
    // numericDims[tempIndex].dispose(); ***I figure it's quicker to store them instead of disposing/deleting. Even when I dispose/delete, the problem still happens.
    // delete numericDims[tempIndex];
    // numericDims.splice(tempIndex,1);
    prt.selectAll("g.handle.left").attr("title",null);
    prt.selectAll("g.handle.right").attr("title",null);
  }
  console.log(numericDims);

Full function:

function dragended(d) {

    let transformation = {
        Y: Math.pow(10, 24),
        Z: Math.pow(10, 21),
        E: Math.pow(10, 18),
        P: Math.pow(10, 15),
        T: Math.pow(10, 12),
        G: Math.pow(10, 9),
        M: Math.pow(10, 6),
        k: Math.pow(10, 3),
        h: Math.pow(10, 2),
        da: Math.pow(10, 1),
        d: Math.pow(10, -1),
        c: Math.pow(10, -2),
        m: Math.pow(10, -3),
        μ: Math.pow(10, -6),
        n: Math.pow(10, -9),
        p: Math.pow(10, -12),
        f: Math.pow(10, -15),
        a: Math.pow(10, -18),
        z: Math.pow(10, -21),
        y: Math.pow(10, -24)
    }

    let reverse = s => {
        let returnValue;
        Object.keys(transformation).some(k => {
            if (s.indexOf(k) > 0) {
                returnValue = parseFloat(s.split(k)[0]) * transformation[k];
                return true;
            }
        })
        return returnValue;
    }


  var facts = window.facts;
  if (d3.select(this).attr("class").indexOf("left")==-1) { var otherHandle = 'left'; } else { var otherHandle = 'right'; }
  d3.select(this).classed("dragging",false);

  var filterFields = window.filterFields;
  var tempIndex = filterFields[0].indexOf(d);
  var min = filterFields[2][tempIndex];
  var max = filterFields[3][tempIndex];
  //console.log(min+', '+max);
  var scale = filterFields[4][tempIndex];
  var t = d3.transform(d3.select(this).attr("transform"));
  var thisX = t.translate[0];
  var flag=0;
  var prt = d3.select("g#f_"+tempIndex);
  var leftHandleX = d3.transform(prt.selectAll("g.handle.left").attr("transform")).translate[0];
  var rightHandleX = d3.transform(prt.selectAll("g.handle.right").attr("transform")).translate[0];

  var wid = prt.selectAll("g.axis").select("rect.numFilterBox").attr("width");
  prt.selectAll("g.axis").select("rect.numFilterBox").attr("x",leftHandleX).attr("width",rightHandleX - leftHandleX);

  var num = -1;
  var pFlag = 0;
  if (filterFields[3][tempIndex]<=1) { var fmt = d3.format('%'); pFlag=1; } else { var fmt = d3.format('4.3s'); }


  if (otherHandle=='left') {
    if (thisX>=300 && scale(min)==0) { flag=1; }
    max = scale.invert(thisX);
    if (isNaN(+fmt(max).trim())) {
      if (pFlag==1) {
        max = +fmt(max).substr(0,fmt(max).length-1)/100
      } else {
        max = reverse(fmt(max));
      }
    } else {
      max = +fmt(max).trim();
    }
    prt.selectAll("g.handle.right").attr("title",function(d){ return 'The filtered maximum for '+filterFields[1][tempIndex]+' is '+max; });

  } else {
    if (thisX<=0 && scale(max)==300) { flag=1; }
    min = scale.invert(thisX);
    if (isNaN(+fmt(min).trim())) {
      if (pFlag==1) {
        min = +fmt(min).substr(0,fmt(min).length-1)/100
      } else {
        min = reverse(fmt(min));
      }
    } else {
      min = +fmt(min).trim();
    }
    prt.selectAll("g.handle.left").attr("title",function(d){ return 'The filtered minimum for '+filterFields[1][tempIndex]+' is '+min; });
  }


  filterFields[2][tempIndex] = min;
  filterFields[3][tempIndex] = max;
  window.filterFields = filterFields;


  if (!numericDims[tempIndex]) {
    console.log('new dimension');
    numericDims[tempIndex] = facts.dimension(function(p){ return p[d]; }); 
  }


  if (flag==0) {
    prt.classed("activeFilter",true);
    numericDims[tempIndex].filterFunction(function(p){ return p>=min && p<=max; });

  } else {
    prt.classed("activeFilter",false);
    numericDims[tempIndex].filterAll();
    // numericDims[tempIndex].dispose();
    // delete numericDims[tempIndex];
    // numericDims.splice(tempIndex,1);
    prt.selectAll("g.handle.left").attr("title",null);
    prt.selectAll("g.handle.right").attr("title",null);


  }
  console.log(numericDims);

  update();
  doHighlight();
  window.dragFlag=1;
}
emma
  • 343
  • 3
  • 16
  • 1
    I don't see any obvious problem here in terms of other places a dimension may be defined. Can you create a working example? It's possible that there is a dimension being defined repeatedly elsewhere in your code. – Ethan Jewett May 26 '17 at 12:43
  • I can't share the entire code unfortunately. But thanks, and yes I think you're right. Do you know: if I declare: dims[1] = facts.dimension() with one accessor, and then run dims[1].dispose(); and dims[1] = facts.dimension() with another accessor, would that cause a fault? It's my workaround to the above problem, but it's a poor one, since it's not working... – emma May 26 '17 at 13:24
  • 1
    That should work. You could also instrument your Crossfilter by doing something like this: `var cfdimfunc = crossfilter.dimension; crossfilter.dimension = function(a) { console.log('New dimension!'); return cfdimfunc(a); }` – Ethan Jewett May 26 '17 at 13:27

0 Answers0