Merge pull request #1326 from nasa/image-brightness-contrast

[Imagery] Brightness/contrast controls
This commit is contained in:
Pete Richards
2016-11-17 11:06:05 -08:00
committed by GitHub
15 changed files with 386 additions and 92 deletions

View File

@@ -2,25 +2,33 @@
<div class="l-image-main-wrapper l-flex-col"
ng-mouseenter="showLocalControls = true;"
ng-mouseleave="showLocalControls = false;">
<div
class="l-local-controls s-local-controls"
ng-show="false && showLocalControls">
<a class="s-button icon-arrow-left"
ng-click="plot.stepBackPanZoom()"
ng-show="1"
title="Restore previous pan/zoom">
</a>
<a class="s-button icon-arrows-out"
ng-click="plot.unzoom()"
ng-show="1"
title="Reset pan/zoom">
</a>
<div class="l-local-controls s-local-controls s-wrapper-transluc l-flex-row"
ng-class="{ 'hide-nice': !showLocalControls }">
<span class="holder flex-elem grows">
<input class="icon-brightness" type="range"
min="0"
max="500"
ng-model="filters.brightness">
</input>
<input class="icon-contrast" type="range"
min="0"
max="500"
ng-model="filters.contrast">
</input>
</span>
<span class="holder flex-elem t-reset-btn-holder">
<a class="s-icon-button icon-reset t-btn-reset"
ng-click="filters = { brightness: 100, contrast: 100 }"></a>
</span>
</div>
<div class="l-image-main s-image-main flex-elem grows"
ng-class="{ paused: imagery.paused(), stale:false }"
mct-background-image="imagery.getImageUrl()">
ng-class="{ paused: imagery.paused(), stale:false }">
<div class="image-main"
mct-background-image="imagery.getImageUrl()"
filters="filters">
</div>
</div>
<div class="l-image-main-controlbar flex-elem l-flex-row">

View File

@@ -66,6 +66,11 @@ define(
);
}
$scope.filters = {
brightness: 100,
contrast: 100
};
// Subscribe to telemetry when a domain object becomes available
$scope.$watch('domainObject', subscribe);

View File

@@ -30,7 +30,13 @@ define(
* property to the URL given in its value, but only after that
* image has loaded; this avoids "flashing" as images change.
*
* If `src` is falsy, no image will be displayed (immediately.)
* If the value of `mct-background-image`is falsy, no image
* will be displayed (immediately.)
*
* Optionally, a `filters` attribute may be specified as an
* object with `brightness` and/or `contrast` properties,
* whose values are percentages. A value of 100 will make
* no changes to the image's brightness or contrast.
*
* @constructor
* @memberof platform/features/imagery
@@ -51,6 +57,15 @@ define(
// do not display out-of-order.
var requested = 0, loaded = 0;
function updateFilters(filters) {
var styleValue = filters ?
Object.keys(filters).map(function (k) {
return k + "(" + filters[k] + "%)";
}).join(' ') :
"";
element.css('filter', styleValue);
}
function nextImage(url) {
var myCounter = requested,
image;
@@ -75,11 +90,15 @@ define(
}
scope.$watch('mctBackgroundImage', nextImage);
scope.$watchCollection('filters', updateFilters);
}
return {
restrict: "A",
scope: { mctBackgroundImage: "=" },
scope: {
mctBackgroundImage: "=",
filters: "="
},
link: link
};
}

View File

@@ -35,7 +35,10 @@ define(
mockDocument = [
jasmine.createSpyObj('document', ['createElement'])
];
mockScope = jasmine.createSpyObj('scope', ['$watch']);
mockScope = jasmine.createSpyObj('scope', [
'$watch',
'$watchCollection'
]);
mockElement = jasmine.createSpyObj('element', ['css']);
testImage = {};
@@ -52,46 +55,70 @@ define(
expect(directive.scope.mctBackgroundImage).toEqual("=");
});
it("watches for changes to the URL", function () {
directive.link(mockScope, mockElement, {});
expect(mockScope.$watch).toHaveBeenCalledWith(
'mctBackgroundImage',
jasmine.any(Function)
);
});
describe("once linked", function () {
beforeEach(function () {
directive.link(mockScope, mockElement, {});
});
it("updates images in-order, even when they load out-of-order", function () {
var firstOnload;
it("watches for changes to the URL", function () {
expect(mockScope.$watch).toHaveBeenCalledWith(
'mctBackgroundImage',
jasmine.any(Function)
);
});
directive.link(mockScope, mockElement);
it("updates images in-order, even when they load out-of-order", function () {
var firstOnload;
mockScope.$watch.mostRecentCall.args[1]("some/url/0");
firstOnload = testImage.onload;
mockScope.$watch.mostRecentCall.args[1]("some/url/0");
firstOnload = testImage.onload;
mockScope.$watch.mostRecentCall.args[1]("some/url/1");
mockScope.$watch.mostRecentCall.args[1]("some/url/1");
// Resolve in a different order
testImage.onload();
firstOnload();
// Resolve in a different order
testImage.onload();
firstOnload();
// Should still have taken the more recent value
expect(mockElement.css.mostRecentCall.args).toEqual([
"background-image",
"url('some/url/1')"
]);
});
// Should still have taken the more recent value
expect(mockElement.css.mostRecentCall.args).toEqual([
"background-image",
"url('some/url/1')"
]);
});
it("clears the background image when undefined is passed in", function () {
directive.link(mockScope, mockElement);
it("clears the background image when undefined is passed in", function () {
mockScope.$watch.mostRecentCall.args[1]("some/url/0");
testImage.onload();
mockScope.$watch.mostRecentCall.args[1](undefined);
mockScope.$watch.mostRecentCall.args[1]("some/url/0");
testImage.onload();
mockScope.$watch.mostRecentCall.args[1](undefined);
expect(mockElement.css.mostRecentCall.args).toEqual([
"background-image",
"none"
]);
});
expect(mockElement.css.mostRecentCall.args).toEqual([
"background-image",
"none"
]);
it("updates filters on change", function () {
var filters = { brightness: 123, contrast: 21 };
mockScope.$watchCollection.calls.forEach(function (call) {
if (call.args[0] === 'filters') {
call.args[1](filters);
}
});
expect(mockElement.css).toHaveBeenCalledWith(
'filter',
'brightness(123%) contrast(21%)'
);
});
it("clears filters when none are present", function () {
mockScope.$watchCollection.calls.forEach(function (call) {
if (call.args[0] === 'filters') {
call.args[1](undefined);
}
});
expect(mockElement.css)
.toHaveBeenCalledWith('filter', '');
});
});
});
}