Skip to main content
Code Review

Return to Revisions

2 of 4
Reordered functions to emphasize the focus of the review
200_success
  • 145.5k
  • 22
  • 190
  • 478

Interdependent color swatch widgets

While writing this code review, I found it necessary to include a live demonstration to illustrate the problems I found, which I implemented using a Stack Snippet with Angular.js.

The demonstration takes a color input and a scalar parameter, and produces two read-only color outputs.

However, the HTML feels a bit repetitive. How can I use Angular more effectively? Optional bonus question: would your advice change if I wanted to present one of the outputs as HSV values instead of RGB?

(For this review, I suggest treating the details of the color manipulation routines as black boxes. For those issues, you may comment on the original answer instead.)

var ColorTweakerCtrl = function ColorTweakerCtrl($scope) {
 $scope.inColor = new RGBColor(234, 150, 0);
 $scope.diff = 127;
 
 $scope.tweak = function tweak() {
 $scope.inColor.r = Math.round($scope.inColor.r);
 $scope.inColor.g = Math.round($scope.inColor.g);
 $scope.inColor.b = Math.round($scope.inColor.b);
 $scope.diff = Math.round($scope.diff);
 $scope.outColor = tweakColor($scope.inColor, $scope.diff);
 $scope.newColor = newTweakColor($scope.inColor, $scope.diff);
 };
 $scope.tweak();
};
function RGBColor(r, g, b) {
 this.r = r; this.g = g; this.b = b;
}
RGBColor.prototype.toString = function() {
 return 'rgb(' + Math.round(this.r) + ',' + Math.round(this.g) + ',' + Math.round(this.b) + ')';
};
/* Based on formulas from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm */
RGBColor.prototype.toHSV = function toHSV() {
 var r = this.r / 255,
 g = this.g / 255,
 b = this.b / 255;
 var cMax = Math.max(r, g, b),
 cMin = Math.min(r, g, b);
 var Δ = cMax - cMin;
 var hue = 60 * ( (cMax == r) ? ((g - b) / Δ) % 6
 : (cMax == g) ? ((b - r) / Δ) + 2
 : ((r - g) / Δ) + 4 );
 var sat = cMax == 0 ? 0 : Δ / cMax;
 var val = cMax;
 return new HSVColor((hue + 360) % 360, sat, val);
}
function HSVColor(h, s, v) {
 this.h = h; this.s = s; this.v = v;
}
HSVColor.prototype.toString = function() {
 return 'hsl(' + Math.round(this.h) + ',' + Math.round(100 * this.s) + '%,' + Math.round(100 * this.v) + '%)';
};
/* http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV */
HSVColor.prototype.toRGB = function toRGB() {
 var c = this.v * this.s;
 var h = this.h / 60;
 var x = c * (1 - Math.abs(h % 2 - 1));
 var r1 = (h < 1 || h >= 5) ? c
 : (h < 2 || h >= 4) ? x : 0;
 var g1 = (h >= 1 && h < 3) ? c
 : (h >= 0 && h < 4) ? x : 0;
 var b1 = (h >= 3 && h < 5) ? c
 : (h >= 2 && h < 6) ? x : 0;
 var m = this.v - c;
 return new RGBColor(Math.round(255 * (r1 + m)),
 Math.round(255 * (g1 + m)),
 Math.round(255 * (b1 + m)));
};
function tweakColor(aColor, aDiff) {
 function intRange(value, min, max) {
 return value < min ? min
 : value > max ? max
 : value;
 }
 var r = aColor.r,
 g = aColor.g,
 b = aColor.b;
 var d = (r + g + b) / 3;
 var dir = (d >= (256 / 2)) ? -aDiff : aDiff;
 r = intRange(r + dir, 0, 255);
 g = intRange(g + dir, 0, 255);
 b = intRange(b + dir, 0, 255);
 return new RGBColor(r, g, b);
}
function newTweakColor(aColor, aDiff) {
 var hsv = aColor.toHSV();
 var vAdj = (aDiff / 128) * (hsv.v - 0.5);
 return (new HSVColor(hsv.h, hsv.s, hsv.v - vAdj)).toRGB();
}
fieldset {
 display: inline-block;
 width: 25%;
}
fieldset#tweak {
 display: block;
 width: 100%;
 border-width: 0;
}
label {
 display: block;
}
.swatch {
 border: 1px solid grey;
 width: 100%;
 height: 1em;
}
input[type=range] {
 width: 40%;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
 <form ng-controller="ColorTweakerCtrl">
 <fieldset id="tweak">
 <label>Diff
 <input ng-model="diff" type="range" min="0" max="255" ng-change="tweak()">
 <input ng-model="diff" type="number" min="0" max="255" ng-change="tweak()">
 </label>
 </fieldset>
 
 <fieldset>
 <legend>Input Color</legend>
 <div class="swatch" style="background-color: {{ inColor.toString() }}"></div>
 <label>R
 <input ng-model="inColor.r" type="range" min="0" max="255" ng-change="tweak()">
 <input ng-model="inColor.r" type="number" min="0" max="255" ng-change="tweak()">
 </label>
 <label>G
 <input ng-model="inColor.g" type="range" min="0" max="255" ng-change="tweak()">
 <input ng-model="inColor.g" type="number" min="0" max="255" ng-change="tweak()">
 </label>
 <label>B
 <input ng-model="inColor.b" type="range" min="0" max="255" ng-change="tweak()">
 <input ng-model="inColor.b" type="number" min="0" max="255" ng-change="tweak()">
 </label>
 </fieldset>
 <fieldset>
 <legend>Output (Original)</legend>
 <div class="swatch" style="background-color: {{ outColor.toString() }}"></div>
 <label>R
 <input ng-model="outColor.r" type="range" min="0" max="255" disabled>
 <input ng-model="outColor.r" type="number" min="0" max="255" disabled>
 </label>
 <label>G
 <input ng-model="outColor.g" type="range" min="0" max="255" disabled>
 <input ng-model="outColor.g" type="number" min="0" max="255" disabled>
 </label>
 <label>B
 <input ng-model="outColor.b" type="range" min="0" max="255" disabled>
 <input ng-model="outColor.b" type="number" min="0" max="255" disabled>
 </label>
 </fieldset>
 <fieldset>
 <legend>Output (Suggested)</legend>
 <div class="swatch" style="background-color: {{ newColor.toString() }}"></div>
 <label>R
 <input ng-model="newColor.r" type="range" min="0" max="255" disabled>
 <input ng-model="newColor.r" type="number" min="0" max="255" disabled>
 </label>
 <label>G
 <input ng-model="newColor.g" type="range" min="0" max="255" disabled>
 <input ng-model="newColor.g" type="number" min="0" max="255" disabled>
 </label>
 <label>B
 <input ng-model="newColor.b" type="range" min="0" max="255" disabled>
 <input ng-model="newColor.b" type="number" min="0" max="255" disabled>
 </label>
 </fieldset>
 </form>
</div>

200_success
  • 145.5k
  • 22
  • 190
  • 478
lang-html

AltStyle によって変換されたページ (->オリジナル) /