cm1.js

Carbon, energy, and other environmental impact calculations for your JavaScript objects. Built for the browser and Node.js.

var ImpactEstimate = require('./impact-estimate'),
  ImpactEstimator = require('./impact-estimator');

var CM1 = module.exports = function() {
  this.attributeMap = {};
};

For a quick, one-off calculation, you can use CM1.impacts. Here's an example for a flight:

var CM1 = require('cm1');
CM1.impacts('flight', {
  origin_airport: 'IAD',
  destination_airport: 'PDX',
  airline: 'United',
  trips: 2,
  segments_per_trip: 1    // nonstop flight
},
function(err, impacts) {
  if(err) return console.log('Argh, falied!', err);

  console.log('Carbon for my cross-country flight: ', impacts.carbon);
  console.log('Methodology: ', impacts.methodology);
});
CM1.impacts = function(type, properties, callback) {
  var model = CM1.model(type, properties);
  model.getImpacts(callback);
};

If you don't want to mess around with prototypes, CM1.model gives you an object that you can define and run calculations on at a later time:

var CM1 = require('cm1');
var model = CM1.model('flight', {
  origin_airport: 'JFK',
  destination_airport: 'Berlin',
  airline: 'Luftansa'
});

// later...
model.seat_class = 'Business';

model.getImpacts(function(err, impacts) {
  if(err) return console.log('Argh, falied!', err);

  console.log('Carbon for my international flight: ', impacts.carbon);
  console.log('Methodology: ', impacts.methodology);
});
CM1.model = function(type, properties) {
  var attributes = Object.keys(properties);

  var proto = function() {};
  CM1.extend(proto, {
    model: type,
    provides: attributes
  });

  var object = new proto();
  for(var i = 0; i < attributes.length; i++) {
    var attribute = attributes[i];
    object[attribute] = properties[attribute];
  }

  return object;
};

You can also turn any object into an impact calculating machine. For example, let's say we have an object representing a rental car:

var RentalCar = function() {};

var car = new RentalCar();
car.make = 'Honda';
car.model = 'Fit';
car.fuelEconomy = 36.7;

Now we want to figure out how much CO2 it emits. CM1.js will add impact calculation powers to your prototype. Before instantiating a RentlCar, use CM1.extend() to tell your prototype how to use CM1 to calculate impacts. The first argument is the prototype to extend, the second argument is a object that describes mappings between properties of your prototype instance to the characteristics sent to CM1. After executing CM1.extend(), A new function called getImpacts() will be added to your class.

var RentalCar = function() {};

CM1.extend(RentalCar, {
  model: 'automobile',
  provides: ['make', 'model', {
    'fuel_efficiency': 'fuelEconomy'
  }
});

This says "my RentalCar prototype will use the Automobile emitter to calculate impacts. It uses the make property to provide make to the web service, model maps to model, and the fuelEconomy property maps to fuel_efficiency on CM1.

Now, we can calculate impacts:

var car = new RentalCar();
car.make = 'Honda';
car.model = 'Fit';
car.fuelEconomy = 36.7;

car.getImpacts(function(err, impacts) {
  if(err) alert("Oops, something broke: " + err);

  alert("My emissions are: " + impacts.carbon);
  alert("My fuel use is: " + impacts.fuelUse);
});

There are a whole bunch of other models available, including computer usage, rail trips, and flights.

CM1.extend = function(klass, mapping) {
  klass.cm1 = new CM1();
  klass.cm1.define(mapping);
  klass.prototype.impactEstimator = new ImpactEstimator(klass.cm1);
  klass.prototype.getImpacts = function(callback) {
    return this.impactEstimator.getImpacts(this, callback);
  };
};

Specifying an API Key

CM1 is free for non-commercial use and available for commercial use. Commercial use requires an API key, and we recommend obtaining a non-commercial key for non-commercial use, as it will prevent rate-limiting. You can get a key at keys.brighterplanet.com.

Once you have your key, you can specify it with:

var CM1 = require('CM1');
process.env.CM1_KEY = 'ABC123';

Note: if using the stand-alone library, process.env won't be available in your browser until you require('CM1').

CM1.prototype.key = function() {
  if(process && process.env && process.env.CM1_KEY)
    return process.env.CM1_KEY;
  else
    return CM1.key;
};

CM1.prototype.define = function(mapping) {
  this.emitAs(mapping.model);
  var provisions = mapping.provide || mapping.provides;
  this.provide(provisions);
};

CM1.prototype.emitAs = function(model) {
  this.model = model;
};

CM1.prototype.provide = function(attributes) {
  for(var i in attributes) {
    if(attributes.hasOwnProperty(i)) {
      var value = attributes[i];
      if(typeof value == 'object') {
        this.provide(value);
      } else if(/^\d+$/.test(i)) {
        this.attributeMap[this.underscore(value)] = value;
      } else {
        this.attributeMap[this.underscore(i)] = value;
      }
    }
  }
};

CM1.prototype.underscore = function(string) {
  return string.replace(/([a-z])([A-Z])/g, function(str, first, second) {
    return first + '_' + second.toLowerCase();
  });
};

CM1.ImpactEstimate = ImpactEstimate;
CM1.ImpactEstimator = ImpactEstimator;
 

Deploy With Browserify

CM1.js can be used with browserify. Simply npm install CM1 and require('CM1') in your code.