Skip to content

Commit

Permalink
Improved BuildingColorBucketCalculator performance
Browse files Browse the repository at this point in the history
Prevent duplicate calls to load cartoLayer
  • Loading branch information
sconnelley committed Jan 20, 2017
1 parent 2c73f36 commit eac0925
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 13 deletions.
73 changes: 64 additions & 9 deletions src/app/models/building_color_bucket_calculator.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,94 @@ define([
this.fieldName = fieldName;
this.buckets = buckets;
this.colorStops = colorStops;


this.memoized = {};
this.memoized.fieldValues = {};
this.memoized.colorGradients = {};
this.memoized.cartoCSS = {};
this.memoized.bucketStops = this.calcBucketStops();
this.memoized.gradientStops = this.calcGradientStops();
};

BuildingColorBucketCalculator.prototype.toBucketStops = function() {


BuildingColorBucketCalculator.prototype.calcBucketStops = function() {
var range = this.colorStops,
buckets = this.buckets,
rangeCount = _.max([range.length - 1, 1]),
domain = _.range(0, buckets, buckets / rangeCount).concat(buckets);

return _.map(domain, function(bucket) { return _.max([0, bucket - 1]); });
};

BuildingColorBucketCalculator.prototype.toGradientStops = function() {

BuildingColorBucketCalculator.prototype.calcGradientStops = function() {
var range = this.colorStops,
buckets = this.buckets,
bucketStops = this.toBucketStops(),
gradientScale = d3.scale.linear().range(range).domain(bucketStops);

return _.map(_.range(buckets), gradientScale);
};

BuildingColorBucketCalculator.prototype.toCartoCSS = function() {
BuildingColorBucketCalculator.prototype.cartoCSS = function() {
if (this.memoized.cartoCSS.hasOwnProperty(this.fieldName)) {
return this.memoized.cartoCSS[this.fieldName];
}

var stops = this.toGradientStops(),
fieldName = this.fieldName,
fieldValues = this.buildings.pluck(fieldName),
gradient = d3.scale.quantile().domain(fieldValues).range(stops);
return _.map(stops, function(stop){
fieldValues = this.getFieldValues(),
gradient = this.colorGradient();

var css = this.memoized.cartoCSS[this.fieldName] = _.map(stops, function(stop){
var min = _.min(gradient.invertExtent(stop));
return "[" + fieldName + ">=" + min + "]{marker-fill:" + stop + "}";
});

return css;
}

BuildingColorBucketCalculator.prototype.getFieldValues = function() {
if (this.memoized.fieldValues.hasOwnProperty(this.fieldName)) {
return this.memoized.fieldValues[this.fieldName];
}

var fieldValues = this.memoized.fieldValues[this.fieldName] = this.buildings.pluck(this.fieldName);

return fieldValues;
};

BuildingColorBucketCalculator.prototype.colorGradient = function() {
if (this.memoized.colorGradients.hasOwnProperty(this.fieldName)) {
return this.memoized.colorGradients[this.fieldName];
}

var stops = this.toGradientStops();
var fieldValues = this.getFieldValues();
var scale = this.memoized.colorGradients[this.fieldName] = d3.scale.quantile().domain(fieldValues).range(stops);

return scale;
}

// Calculated in constructor
BuildingColorBucketCalculator.prototype.toBucketStops = function() {
return this.memoized.bucketStops;
}

// Calculated in constructor
BuildingColorBucketCalculator.prototype.toGradientStops = function() {
return this.memoized.gradientStops;
}

BuildingColorBucketCalculator.prototype.toCartoCSS = function() {
return this.cartoCSS();
};

BuildingColorBucketCalculator.prototype.toColor = function(value) {
var stops = this.toGradientStops(),
fieldValues = this.buildings.pluck(this.fieldName),
gradient = d3.scale.quantile().domain(fieldValues).range(stops);
var gradient = this.colorGradient();

return gradient(value);
};

Expand Down
10 changes: 6 additions & 4 deletions src/app/views/building_comparison/building_comparison.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ define([
}, this);
};


ReportTranslator.prototype.updateMetrics = function(buildings, metricFields) {
var metrichash = metricFields.toString();

Expand All @@ -40,8 +41,9 @@ define([
if (currentMetricHash === metrichash) return;

var metrics = _.map(metricFields, function(field) {
var value = building.get(field),
color = this.gradientCalculators[field].toColor(value);
var value = building.get(field);
var color = this.gradientCalculators[field].toColor(value); // ~5ms

return {
value: value,
color: color,
Expand All @@ -53,6 +55,7 @@ define([
this.lookup[id].metrics = metrics;
this.lookup[id].metrichash = metrichash;
}, this);

};

ReportTranslator.prototype.toRows = function(buildings) {
Expand Down Expand Up @@ -191,7 +194,6 @@ define([
buildingId = this.state.get('city').get('property_id');

this.report = new ReportTranslator(buildingId, buildingFields, buildings, gradientCalculators);

this.updateBuildings();
},

Expand All @@ -201,8 +203,8 @@ define([

updateBuildings: function() {
if (!this.buildingsExist()) return;
this.buildings = this.allBuildings.toFilter(this.allBuildings, this.state.get('categories'), this.state.get('filters'));

this.buildings = this.allBuildings.toFilter(this.allBuildings, this.state.get('categories'), this.state.get('filters'));
this.preCalculateTable();
this.onSort(true);
},
Expand Down
6 changes: 6 additions & 0 deletions src/app/views/map/building_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ define([
this.cartoLayer.getSubLayer(0).set(this.toCartoSublayer()).show();
return this;
}

// skip if we are loading `cartoLayer`
if (this.cartoLoading) return;

this.cartoLoading = true;
cartodb.createLayer(this.leafletMap, {
user_name: this.allBuildings.cartoDbUser,
type: 'cartodb',
Expand All @@ -221,6 +226,7 @@ define([
return this;
},
onCartoLoad: function(layer) {
this.cartoLoading = false;
var sub = layer.getSubLayer(0);
this.cartoLayer = layer;
sub.setInteraction(true);
Expand Down

0 comments on commit eac0925

Please sign in to comment.