Skip to content

Commit

Permalink
Redo scalerange calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
ConnorStroomberg committed Oct 23, 2014
1 parent 0c0741f commit b977722
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 50 deletions.
25 changes: 2 additions & 23 deletions app/js/controllers/scaleRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,29 +72,8 @@ define(['mcda/config', 'angular', 'underscore'], function(Config, angular, _) {
};

// Set scales for slider
var margin = 0.5 * (ScaleRangeService.nice(to) - ScaleRangeService.nice(from));
var scale = state.problem.criteria[criterion[0]].scale || [null, null];
scale[0] = _.isNull(scale[0]) ? -Infinity : scale[0];
scale[1] = _.isNull(scale[1]) ? Infinity : scale[1];

var boundFrom = function(val) {
return val < scale[0] ? scale[0] : val;
};
var boundTo = function(val) {
return val > scale[1] ? scale[1] : val;
};
scales[criterion[0]] = {
restrictFrom: criterionRange[0],
restrictTo: criterionRange[1],
from: boundFrom(ScaleRangeService.nice(from) - margin),
to: boundTo(ScaleRangeService.nice(to) + margin),
increaseFrom: function() {
this.from = boundFrom(this.from - margin);
},
increaseTo: function() {
this.to = boundTo(this.to + margin);
}
};
var criterionScale = state.problem.criteria[criterion[0]].scale;
scales[criterion[0]] = ScaleRangeService.calculateScales(criterionScale, from, to, criterionRange);

});
$scope.currentStep = _.extend(state, {
Expand Down
9 changes: 4 additions & 5 deletions app/js/directives.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ define(['require', 'underscore', 'jQuery', 'angular', 'd3', 'nvd3'], function(re

var directives = angular.module('elicit.directives', []);

directives.directive('slider', function() {
directives.directive('slider', function($filter) {
var initialize = function(scope, $element) {
var type = scope.type;
var from = scope.range.from;
Expand All @@ -25,13 +25,12 @@ define(['require', 'underscore', 'jQuery', 'angular', 'd3', 'nvd3'], function(re
--steps;
}

var precision = 3;
var stepToValue = function(step) {
return (from + (step / steps) * delta).toFixed(precision);
return $filter('number')((from + (step / steps) * delta));
};

function valueToStep(value) {
return ((value - from) / delta * steps).toFixed(precision);
return $filter('number')(((value - from) / delta * steps));
}

function getModelValue() {
Expand Down Expand Up @@ -91,7 +90,7 @@ define(['require', 'underscore', 'jQuery', 'angular', 'd3', 'nvd3'], function(re
link: function(scope, $element) {
var init = function() {
if (scope.range) {
console.log('range from' + scope.range.from + ' to ' + scope.range.to)
console.log('range from' + scope.range.from + ' to ' + scope.range.to);
initialize(scope, $element);
}
};
Expand Down
84 changes: 72 additions & 12 deletions app/js/services/scaleRangeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,81 @@ define(['angular'],

var ScaleRangeService = function() {

function nice(x) {
var log10 = function(y) {
return Math.log(y) / Math.log(10);
};
var negative = x < 0;
var absX = Math.abs(x);
var val = Math.pow(10, Math.floor(log10(absX)));
var nice = _.find(_.range(1, 11), function(n) {
return absX <= val * n;
});
return (negative ? -1 : 1) * (val * nice);
var log10 = function(x) {
return Math.log(x) / Math.log(10);
};

function nice(x, dirFun) {
if(x === 0) return 0;
var absX = Math.abs(x);
var log10X = log10(absX);
var factor;
var normalised;
var ceiled;
var deNormalised;
if (absX >= 1) {
factor = Math.floor(log10X);
normalised = x / Math.pow(10, factor);
ceiled = dirFun(normalised);
deNormalised = ceiled * Math.pow(10, factor);
} else {
factor = Math.ceil(Math.abs(log10X));
normalised = x * Math.pow(10, factor);
ceiled = dirFun(normalised);
deNormalised = ceiled * Math.pow(10, -factor);
}

// console.log('when x=' + x + ' log10X = ' + log10X);
// console.log('when x=' + x + ' factor = ' + factor);
// console.log('when x=' + x + ' normalised = ' + normalised);
// console.log('when x=' + x + ' ceiled = ' + ceiled);
// console.log('when x=' + x + ' deNormalised = ' + deNormalised);

return deNormalised;
}

function niceTo(x) {
return nice(x, Math.ceil);
}

function niceFrom(x) {
return nice(x, Math.floor);
}


function calculateScales(criterionScale, from, to, criterionRange) {
var
boundFrom = function(val) {
return val < scale[0] ? scale[0] : val;
},
boundTo = function(val) {
return val > scale[1] ? scale[1] : val;
},
margin = 0.5 * (to - from),
scale = criterionScale || [null, null];

scale[0] = _.isNull(scale[0]) ? -Infinity : scale[0];
scale[1] = _.isNull(scale[1]) ? Infinity : scale[1];

return {
restrictFrom: criterionRange[0],
restrictTo: criterionRange[1],
from: niceFrom(from),
to: niceTo(to),
increaseFrom: function() {
this.from = niceFrom(boundFrom(this.from - margin));
},
increaseTo: function() {
this.to = niceTo(boundTo(this.to + margin));
}
};
}

return {
nice: nice
nice: nice,
niceTo: niceTo,
niceFrom: niceFrom,
calculateScales: calculateScales
};
};

Expand Down
62 changes: 52 additions & 10 deletions test/unit/scaleRangeServiceSpec.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,64 @@
define(['angular', 'angular-mocks', 'mcda/services/scaleRangeService'], function() {

// - the lower bound must be lower than the lower end of the observed range
// - the upper bound should be higher than the upper end of the observed range
// - the values should be "nice" (have no more than two significant digits, preferably only one)

// - the lower bound must be greater than or equal to the theoretical lower bound
// - the upper bound must be smaller than or equal to the theoretical upper bound


describe('The scaleRange service', function() {

var a;
beforeEach(module('elicit.scaleRangeService'));

describe('nice', function() {
describe('calculateScales', function() {
it('on unbounded scales, bounds should lie outside the observed range', inject(function(ScaleRangeService) {
var criterionScale = [null, null];
var from = -16.123;
var to = -12.123;
var criterionRange = [from, to];

beforeEach(module('elicit.scaleRangeService'));
var result = ScaleRangeService.calculateScales(criterionScale, from, to, criterionRange);
expect(result.from).toEqual(-20);
expect(result.to).toEqual(-10);
}));
});

describe('niceFrom', function() {
it('should', inject(function(ScaleRangeService) {
expect(ScaleRangeService.niceFrom(150)).toEqual(100);
expect(ScaleRangeService.niceFrom(15)).toEqual(10);
expect(ScaleRangeService.niceFrom(1.5)).toEqual(1);
expect(ScaleRangeService.niceFrom(0.15)).toEqual(0.1);
expect(ScaleRangeService.niceFrom(0.015)).toEqual(0.01);

beforeEach(function() {
expect(ScaleRangeService.niceFrom(-150)).toEqual(-200);
expect(ScaleRangeService.niceFrom(-15)).toEqual(-20);
expect(ScaleRangeService.niceFrom(-1.5)).toEqual(-2);
expect(ScaleRangeService.niceFrom(-0.15)).toEqual(-0.2);
expect(ScaleRangeService.niceFrom(-0.015)).toEqual(-0.02);

});
expect(ScaleRangeService.niceFrom(0)).toEqual(0);

}));
});
describe('niceTo', function() {
it('should', inject(function(ScaleRangeService) {
expect(ScaleRangeService.niceTo(150)).toEqual(200);
expect(ScaleRangeService.niceTo(15)).toEqual(20);
expect(ScaleRangeService.niceTo(1.5)).toEqual(2);
expect(ScaleRangeService.niceTo(0.15)).toEqual(0.2);
expect(ScaleRangeService.niceTo(0.015)).toEqual(0.02);

it('should do something',
inject(function($rootScope, ScaleRangeService) {
expect(ScaleRangeService.nice(-16)).toEqual(-20);
}));
expect(ScaleRangeService.niceTo(-150)).toEqual(-100);
expect(ScaleRangeService.niceTo(-15)).toEqual(-10);
expect(ScaleRangeService.niceTo(-1.5)).toEqual(-1);
expect(ScaleRangeService.niceTo(-0.15)).toEqual(-0.1);
expect(ScaleRangeService.niceTo(-0.015)).toEqual(-0.01);

expect(ScaleRangeService.niceTo(0)).toEqual(0);
}));
});
});
});

0 comments on commit b977722

Please sign in to comment.