d3-legend icon indicating copy to clipboard operation
d3-legend copied to clipboard

allow labels functions to return Promise (resolving with label text)

Open christophe-g opened this issue 5 years ago • 2 comments

Motivation: fetch label text async (e.g. based on locale)

No breaking changes.

const asyncHelper = (  i,
  genLength,
  generatedLabels,
  labelDelimiter) => {
    // get a text value stored in firebase
   return firebase.database().ref(pathToLocaleText).once('value').then(snap =>{
    return snap.val();
  })

}

example: image

var thresholdScale = d3.scaleThreshold()
  .domain([0, 1000, 2500, 5000, 10000])
  .range(d3.range(6)
    .map(function(i) { return "q" + i + "-9" }));

var linear = d3.scaleLinear()
  .domain([0, 10])
  .range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]);

// ----legendHelpers.thresholdLabels----
const promiseHelper = function({
  i,
  genLength,
  generatedLabels,
  labelDelimiter
}) {

  //
  const promise =  Promise.resolve()
    .then(function() {
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          let res;
          if (i === 0) {
            const values = generatedLabels[i].split(` ${labelDelimiter} `);
            return resolve(`Less than ${values[1]}`);
          } else if (i === genLength - 1) {
            const values = generatedLabels[i].split(` ${labelDelimiter} `);
            return resolve(`${values[0]} or more`);
          }
          return resolve(generatedLabels[i]);
        }, 100);
      });
    });

  return promise;  
};

// ----legendHelpers.thresholdLabels----
const helper = function({
  i,
  genLength,
  generatedLabels,
  labelDelimiter
}) {

  if (i === 0) {
    const values = generatedLabels[i].split(` ${labelDelimiter} `);
    return `Less than ${values[1]}`;
  } else if (i === genLength - 1) {
    const values = generatedLabels[i].split(` ${labelDelimiter} `);
    return `${values[0]} or more`;
  }
  return generatedLabels[i];
};

const legend = d3.legendColor()
  .labelFormat(d3.format('.2f'))
  .title('Sync labels')
  .labels(helper)
  .useClass(true)
  .scale(thresholdScale);

const promiseLegend = d3.legendColor()
  .labelFormat(d3.format('.2f'))
  .title('Async labels (Promise)')
  .labels(promiseHelper)
  .useClass(true)
  .scale(thresholdScale);



d3.select('#legend .legend')
  .call(legend);

d3.select('#promiseLegend .legend')
  .call(promiseLegend);

christophe-g avatar Jul 22 '18 14:07 christophe-g

Thanks for putting this together. Do you know of package to polyfill Promises? I want this package to still be able to work in IE. I tried using the babel-plugin-es6-promise but ran into a grunt error that was difficult to decipher.

susielu avatar Aug 04 '18 17:08 susielu

Randomly looking since I submitted a pull request. We used es6-shim and/or core.js to poly promises...

tonym97 avatar Feb 20 '19 14:02 tonym97