diff --git a/easy/buzz_lightyear/js/buzz_lightyear.js b/easy/buzz_lightyear/js/buzz_lightyear.js index 852dd46..eb456cc 100644 --- a/easy/buzz_lightyear/js/buzz_lightyear.js +++ b/easy/buzz_lightyear/js/buzz_lightyear.js @@ -6,5 +6,15 @@ $(document).ready(function() { // Put code here... + values = [1.0/0, -1.0/0, 1e17, true, false]; + $("#output").append("Checking these values: " + values); -}); \ No newline at end of file + $.each(values, function(key, x){ + if (x == x + 2) { + $('#output').append("
When x = " + x + " then x == x + 2 evaluates to true!
"); + } else { + $('#output').append("When x = " + x + " then x == x + 2 evaluates to false!
"); + } + }); + +}); diff --git a/easy/buzz_lightyear/php/buzz_lightyear.php b/easy/buzz_lightyear/php/buzz_lightyear.php index 7dfe56d..d38709e 100644 --- a/easy/buzz_lightyear/php/buzz_lightyear.php +++ b/easy/buzz_lightyear/php/buzz_lightyear.php @@ -6,7 +6,16 @@ * Give all possible values of `$x` where `$x == $x + 2;` will evaluate to `true` */ +$values = array(1e17, PHP_INT_MAX, true); +foreach ($values as $x) { + if ($x == $x + 2) { + echo '$x == $x + 2; evaluates to true when $x = ?' . "\n"; + echo "\n";var_export($x);echo "\n"; + var_dump($x == $x + 2); + echo "\n\n"; + } +} ?> \ No newline at end of file diff --git a/easy/buzz_lightyear/ruby/buzz_lightyear.rb b/easy/buzz_lightyear/ruby/buzz_lightyear.rb index a95b225..3b3760a 100644 --- a/easy/buzz_lightyear/ruby/buzz_lightyear.rb +++ b/easy/buzz_lightyear/ruby/buzz_lightyear.rb @@ -1,3 +1,9 @@ # Buzz Lightyear Code Challenge # -# Give all possible values of `x` where `x == x + 2` will evaluate to `true` \ No newline at end of file +# Give all possible values of `x` where `x == x + 2` will evaluate to `true` + +start_time = Time.now + +[1.0/0, -1.0/0, 1e17].each { |x| p "#{x} evaluates to true" if x == x + 2 } + +puts "\nCompleted in #{Time.now - start_time} ms" diff --git a/easy/fibonacci_series/php/fibonacci_series.php b/easy/fibonacci_series/php/fibonacci_series.php index efd32be..d9efe2e 100644 --- a/easy/fibonacci_series/php/fibonacci_series.php +++ b/easy/fibonacci_series/php/fibonacci_series.php @@ -36,7 +36,31 @@ $lines = file($argv[1]); +foreach ($lines as $n) { + $fibber = new Fibber(); + echo "Finding Fibonacci value at position {$n}: " . $fibber->fib_a($n) . "\n"; +} + +final class Fibber +{ + public function fib_a($n) + { + $n = (int)$n; + + if ($n < 2) { + return $n; + } else { + $vals = array(0,1); + $i = $n - 1; + while ($i <= $n) { + $vals[] = $vals[count($vals) - 1] + $vals[count($vals) - 2]; + } + + return end($vals); + } + } +} ?> \ No newline at end of file diff --git a/easy/fibonacci_series/ruby/fibonacci_series.rb b/easy/fibonacci_series/ruby/fibonacci_series.rb index 3f97a59..a093dae 100644 --- a/easy/fibonacci_series/ruby/fibonacci_series.rb +++ b/easy/fibonacci_series/ruby/fibonacci_series.rb @@ -1,29 +1,38 @@ # == Fibonacci Series Code Challenge # -# The Fibonacci series is defined as: -# -# F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2) when n > 1; -# +# The Fibonacci series is defined as: +# +# F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2) when n > 1; +# # Given a positive integer 'n', print out the F(n). -# +# # -- Example Input: -# +# # 5 # 12 -# -# +# +# # -- Example Output: -# +# # 5 # 144 # # # ARGV[0] should be the text file you pass in when you call this script -# +# # -- Example: -# +# # $ ruby fibonacci_series.rb list.txt -# -File.open(ARGV[0]).each_line do |line| +# + +start_time = Time.now + +File.open(ARGV[0]).each_line do |n| # begin coding here + + # Hash memoization + fibonacci = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2] } + puts fibonacci[n.to_i] end + +puts "\nCompleted in #{Time.now - start_time} ms" diff --git a/easy/fizz_buzz/php/fizz_buzz.php b/easy/fizz_buzz/php/fizz_buzz.php index aaa1c27..0eb2331 100644 --- a/easy/fizz_buzz/php/fizz_buzz.php +++ b/easy/fizz_buzz/php/fizz_buzz.php @@ -6,11 +6,37 @@ * Write a program that prints out the pattern generated by playing * a variation of the Fizz Buzz game where we'll count from 1 to 100 * replacing any number divisible by four with `Fizz`, any number - * divisible by six with `Buzz`, any number divisible by either four or six + * divisible by six with `Buzz`, any number divisible by both four and six * with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with * `Fizz Buzz BOOM`. */ +$start = microtime(); + +foreach(range(1, 100) as $n) { + switch (true) { + case($n % 24 == 0): + echo "Fizz Buzz BOOM\n"; + break; + case($n % 4 == 0 && $n % 6 == 0): + echo "Fizz Buzz\n"; + break; + case($n % 6 == 0): + echo "Buzz\n"; + break; + case($n % 4 == 0): + echo "Fizz\n"; + break; + default: + echo "$n\n"; + break; + } +} + +$end = microtime(); +$time = $end - $start; + +echo "\nCompleted in " . $time . " ms"; diff --git a/easy/fizz_buzz/ruby/fizz_buzz.rb b/easy/fizz_buzz/ruby/fizz_buzz.rb index d787cdb..6aa8d40 100644 --- a/easy/fizz_buzz/ruby/fizz_buzz.rb +++ b/easy/fizz_buzz/ruby/fizz_buzz.rb @@ -1,8 +1,22 @@ #== Fizz Buzz Code Challenge -# -# Write a program that prints out the pattern generated by playing -# a variation of the Fizz Buzz game where we'll count from 1 to 100 -# replacing any number divisible by four with `Fizz`, any number -# divisible by six with `Buzz`, any number divisible by either four or six -# with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with +# +# Write a program that prints out the pattern generated by playing +# a variation of the Fizz Buzz game where we'll count from 1 to 100 +# replacing any number divisible by four with `Fizz`, any number +# divisible by six with `Buzz`, any number divisible by either four or six +# with `Fizz Buzz`, and any number divisible by the product of `4 x 6` with # `Fizz Buzz BOOM`. + +start_time = Time.now + +(1..100).to_a.each do |n| + case true + when n % 24 == 0 then puts 'Fizz Buzz BOOM' + when n % 12 == 0 then puts 'Fizz Buzz' + when n % 6 == 0 then puts 'Buzz' + when n % 4 == 0 then puts 'Fizz' + else puts n + end +end + +puts "\nCompleted in #{Time.now - start_time} ms" diff --git a/easy/odd_numbers/js/odd_numbers.js b/easy/odd_numbers/js/odd_numbers.js index ec0eee9..19c4b72 100644 --- a/easy/odd_numbers/js/odd_numbers.js +++ b/easy/odd_numbers/js/odd_numbers.js @@ -6,5 +6,9 @@ $(document).ready(function() { // Put code here... - -}); \ No newline at end of file + for (i=1; i<=99; i++) { + if (i % 2 != 0) { + $("#output").append('' + i + '
'); + } + } +}); \ No newline at end of file diff --git a/easy/odd_numbers/php/odd_numbers.php b/easy/odd_numbers/php/odd_numbers.php index ee926ef..ba9c77d 100644 --- a/easy/odd_numbers/php/odd_numbers.php +++ b/easy/odd_numbers/php/odd_numbers.php @@ -7,7 +7,15 @@ * one number per line to the console (STDOUT) */ +$start = microtime(); +foreach(range(1, 99) as $number) { + echo $n = ($number % 2 != 0) ? "{$number}\n" : ''; +} +$end = microtime(); +$time = $end - $start; + +echo "\nCompleted in " . $time . " ms"; ?> \ No newline at end of file diff --git a/easy/odd_numbers/ruby/odd_numbers.rb b/easy/odd_numbers/ruby/odd_numbers.rb index cae7e37..fbe317b 100644 --- a/easy/odd_numbers/ruby/odd_numbers.rb +++ b/easy/odd_numbers/ruby/odd_numbers.rb @@ -1,4 +1,10 @@ # Odd Numbers Code Challenge # -# Write a program to print the odd numbers from 1 to 99, +# Write a program to print the odd numbers from 1 to 99, # one number per line to the console (STDOUT) + +start_time = Time.now + +(1..99).to_a.each { |n| p n unless n % 2 == 0 } + +puts "\nCompleted in #{Time.now - start_time} ms" diff --git a/easy/reverse_words/js/reverse_words.js b/easy/reverse_words/js/reverse_words.js index ec0eee9..f2d2369 100644 --- a/easy/reverse_words/js/reverse_words.js +++ b/easy/reverse_words/js/reverse_words.js @@ -6,5 +6,9 @@ $(document).ready(function() { // Put code here... - -}); \ No newline at end of file + var lines = $('#input pre').text().split('\n'); + $.each(lines, function(n, line) { + reversed = line.split(" ").reverse().join(" "); + $('#output').append('' + reversed + '
'); + }); +}); diff --git a/easy/reverse_words/js/styles.css b/easy/reverse_words/js/styles.css index e0fd177..d823a5b 100644 --- a/easy/reverse_words/js/styles.css +++ b/easy/reverse_words/js/styles.css @@ -9,12 +9,12 @@ body { code { background: #efefef; padding: 2px 4px; - color: #c30; + color: #c30; } -p { - line-height: 1.75em; - margin-bottom: 1.2em; +p { + line-height: 1.75em; + margin-bottom: 1.2em; } strong { font-weight: bold; } @@ -28,39 +28,39 @@ strong { font-weight: bold; } #wrapper header { border-bottom: 1px solid #ddd; - padding: 0 0 0.8em; + padding: 0 0 0.8em; } -#wrapper header h1 { - font-size: 32px; - margin: 0.5em 0 1.2em; +#wrapper header h1 { + font-size: 32px; + margin: 0.5em 0 1.2em; } -#wrapper h1 small { - font-size: 0.65em; +#wrapper h1 small { + font-size: 0.65em; color: #ddd; -} +} -#wrapper h1 small .difficulty { +#wrapper h1 small .difficulty { color: #c30; text-align: right; -} +} -#wrapper header h3 { - font-size: 16px; - color: #3cc; - margin-bottom: 1.2em; +#wrapper header h3 { + font-size: 16px; + color: #3cc; + margin-bottom: 1.2em; } #wrapper .sample { background: #ededed; - color: #777; + color: #777; border: 1px solid #cdcdcd; margin: 20px 0; } -#wrapper .sample pre { - padding: 10px 10px 0; +#wrapper .sample pre { + padding: 10px 10px 0; } #wrapper #output { @@ -69,3 +69,8 @@ strong { font-weight: bold; } color: #3cc; background: #3c3c3c; } + +#wrapper #output p { + line-height: 1.2em; + margin-bottom: 0; +} diff --git a/easy/reverse_words/php/reverse_words.php b/easy/reverse_words/php/reverse_words.php index f9f685c..caddb76 100644 --- a/easy/reverse_words/php/reverse_words.php +++ b/easy/reverse_words/php/reverse_words.php @@ -2,7 +2,7 @@ /** * Reverse Words Code Challenge * - * Write a method to reverse the words of an input sentence. + * Write a method to reverse the words of an input sentence. * Reverse and print out each line's content as a new line to the console. * * @@ -17,7 +17,7 @@ * World Hello * Ash August * - * To access the text file you can either hard code it in here + * To access the text file you can either hard code it in here * or make it a command line argument like so: * * $ php reverse_words.php list.txt @@ -30,7 +30,24 @@ * * $lines = file('list.txt'); */ + +$start_time = microtime(); + $lines = file($argv[1]); +foreach ($lines as $lineNumber => $line) { + if (!empty($line)) { + $str = preg_replace('/[\r\n]+/', '', $line); + $arr = explode(' ', $str); + $reversedArr = array_reverse($arr); + $reversedStr = join(' ', $reversedArr); + echo $reversedStr . "\n"; + } +} + +$end_time = microtime(); +$time = $end_time - $start_time; + +echo "\nCompleted in " . $time . " ms"; -?> \ No newline at end of file +?> diff --git a/easy/reverse_words/ruby/reverse_words.rb b/easy/reverse_words/ruby/reverse_words.rb index d29fb86..6846ba6 100644 --- a/easy/reverse_words/ruby/reverse_words.rb +++ b/easy/reverse_words/ruby/reverse_words.rb @@ -1,29 +1,36 @@ ############################################# # == Reverse Words Code Challenge # ############################################# -# -# Write a method to reverse the words of an input sentence. +# +# Write a method to reverse the words of an input sentence. # Reverse and print out each line's content as a new line to the console. -# -# +# +# # -- Example Input: -# +# # Hello World # August Ash -# -# +# +# # -- Example Output: -# +# # World Hello # Ash August # # # ARGV[0] should be the text file you pass in when you call this script -# +# # -- Example: -# +# # $ ruby reverse_words.rb list.txt -# +# + +start_time = Time.now + File.open(ARGV[0]).each_line do |line| # begin coding here + puts line.split(' ').reverse.join(' ') end + +puts "\nCompleted in #{Time.now - start_time} ms" + diff --git a/hard/color_contrast_calculator/calculator.js b/hard/color_contrast_calculator/calculator.js new file mode 100644 index 0000000..824590d --- /dev/null +++ b/hard/color_contrast_calculator/calculator.js @@ -0,0 +1,553 @@ +/*jslint plusplus: true, todo: true, white: true */ +/*global jQuery, $, Raphael */ + +/** + * jQuery version 1.8.2 + * + * DOM READY! + */ +$(document).ready(function(){ + // Put code here... + var colorsData = $("#colors").attr('data-color-values'); + var colors = $.parseJSON(colorsData); + + // console.log(colors); + + new ColorContrastCalculator({ + data: colors, + fgGridHeaderText: "Raised Text Color", + bgGridHeaderText: "Face Material", + fontFace: "TuffyRegular, Helvetica, sans-serif", + textColor: '#363636' + }); + +}); + +/** + * ColorContrastCalculator + * + * draws an interactive grid of colors with a preview area + * to help determine what foreground/background color combination + * offers the best contrast and will be compliant with the + * Americans with Disabilities Act (ADA) requirement of 70% + * contrast value. + */ +function ColorContrastCalculator(config) { + // make sure our class is called with our new arguments + if (!(this instanceof arguments.callee)) { + return new arguments.callee(arguments); + } + + // keep track of the desired scope + var self = this; + + /** + * initialize the Raphael drawing space + * and parses the data into its major components + * (i.e., color swatch grids, labels, preview) + */ + self.init = function() { + // the data of course + self.data = config.data || []; + + /** + * Raphael canvas options + */ + // element to render the Raphael canvas to + self.domID = config.renderTo || 'output'; + + // specify a definite width for the Raphael canvas; + // otherwise defaults to the width of the containing element (domID) + self.width = config.width || $("#" + self.domID).width(); + + // specify the definite height for the Raphael canvas + self.height = config.height || 540; + + // The actual Raphael canvas object + self.paper = Raphael(self.domID, self.width, self.height); + + // the width of the space between columns (global value) + self.gutter = config.gutter || 20; + + /** + * Swatch/Tile options + */ + + // width & height of the swatches/tiles + self.tileWidth = config.tileWidth || 36; + self.tileHeight = config.tileHeight || 36; + + // number color swatches/tiles per row + self.tilesPerRow = config.tilesPerRow || 10; + + // the width of the space/gutter between swatches/tiles + self.tileGutter = config.tileGutter || self.gutter * 0.5; + + // the height of the space/gutter between foreground and background grids + self.gridGutter = config.gridGutter || self.gutter * 2; + + self.fgGridHeaderText = config.fgGridHeaderText || 'Foreground Color'; + self.bgGridHeaderText = config.bgGridHeaderText || 'Background Color'; + + + /** + * Font/Text options + */ + self.fontFace = config.fontFace || "'Trade Gothic', 'Helvetice Nueue', 'Helvetica', 'Arial', sans-serif"; + self.headerFontSize = config.headerFontSize || 24; + self.gridHeaderFontSize = config.gridHeaderFontSize || self.headerFontSize; + self.sectionHeaderFontSize = config.sectionHeaderFontSize || self.headerFontSize * 0.833333; + self.textFontSize = config.textFontSize || self.headerFontSize * 0.583333; + self.textColor = config.textColor || "#222"; + + self.fontAttrs = { + 'fill': self.textColor, + 'stroke': 'transparent', + 'font-family': self.fontFace, + 'text-anchor': 'start' + }; + + /** + * Preview/Chosen color box options + */ + self.boxWidth = config.boxWidth || (self.tileWidth + self.tileGutter) * 6; + self.boxHeight = config.boxHeight || self.boxWidth / 2; + + /** + * ADA guidelines require that copy characters contrast + * with their background by at least 70%. + * + * @see http://www.access-board.gov/adaag/html/adaag.htm + */ + self.adaMinContrastValue = config.adaMinContrastValue || 70; + + + /** + * complex paths + */ + self.uncheckedBox = "M26,27.5H6c-0.829,0-1.5-0.672-1.5-1.5V6c0-0.829,0.671-1.5,1.5-1.5h20c0.828,0,1.5,0.671,1.5,1.5v20C27.5,26.828,26.828,27.5,26,27.5zM7.5,24.5h17v-17h-17V24.5z"; + + self.checkedBox = "M29.548,3.043c-1.081-0.859-2.651-0.679-3.513,0.401L16,16.066l-3.508-4.414c-0.859-1.081-2.431-1.26-3.513-0.401c-1.081,0.859-1.261,2.432-0.401,3.513l5.465,6.875c0.474,0.598,1.195,0.944,1.957,0.944c0.762,0,1.482-0.349,1.957-0.944L29.949,6.556C30.809,5.475,30.629,3.902,29.548,3.043zM24.5,24.5h-17v-17h12.756l2.385-3H6C5.171,4.5,4.5,5.171,4.5,6v20c0,0.828,0.671,1.5,1.5,1.5h20c0.828,0,1.5-0.672,1.5-1.5V12.851l-3,3.773V24.5z"; + + /** + * business time! organize the data and draw everything + */ + self.parseData(); + self.draw(); + }; + + /** + * utility function to separate out the foreground and background + * colors into their own arrays + * + * TODO: what if the foreground and background colors are an array? + */ + self.parseData = function() { + self.fgColors = []; + self.bgColors = []; + + // convert the foreground colors into an array of objects + $.each(self.data.foreground, function(i, color){ + self.fgColors.push(color); + }); + + // convert the background colors into an array of objects + $.each(self.data.background, function(i, color){ + self.bgColors.push(color); + }); + + // calculate the number of rows + self.calculateRowsNeeded(); + + // calculate the total height of all grids, headers, etc. + // so the canvas can be resized to fit + self.calculateTotalHeight(); + }; + + /** + * calculate how many rows are needed for each grid (background & foreground) + * by dividing their quantity by the self.tilesPerRow configuration value + */ + self.calculateRowsNeeded = function() { + self.fgRows = Math.ceil(self.fgColors.length / self.tilesPerRow); + self.bgRows = Math.ceil(self.bgColors.length / self.tilesPerRow); + }; + + /** + * re-calculates the height needed for the canvas to be rendered fully + * by accounting for grid headers + margins + grid rows and margins + */ + self.calculateTotalHeight = function() { + var bgGridHeight, fgGridHeight, gridHeaderHeightWithMargin; + + self.gridHeaderMargin = (self.gridGutter / 2); + + gridHeaderHeightWithMargin = self.gridHeaderFontSize + self.gridHeaderMargin; + bgGridHeight = (self.tileHeight + self.tileGutter) * self.bgRows; + fgGridHeight = (self.tileHeight + self.tileGutter) * self.fgRows; + + self.fgGridHeight = gridHeaderHeightWithMargin + fgGridHeight; + self.bgGridHeight = gridHeaderHeightWithMargin + bgGridHeight; + self.gridWidth = ((self.tileWidth + self.tileGutter) * self.tilesPerRow) + self.gridGutter; + + // set the new height of the canvas paper + self.height = self.fgGridHeight + self.gridGutter + self.bgGridHeight; + + // resize the Raphael canvas to it's new dimensions + self.paper.setSize(self.width, self.height); + }; + + /** + * utilty function responsible for drawing the grid of colors + * for foreground and background colors, chosen color values, + * and the preview area + */ + self.draw = function() { + self.drawSections(self.fgColors, self.drawForegroundColorGrid); + self.drawSections(self.bgColors, self.drawBackgroundColorGrid); + self.drawPreview(); + }; + + /** + * == drawSections + * + * pass the data onto the appropriate drawing methods + */ + self.drawSections = function(theArray, drawingCallback) { + drawingCallback(theArray); + }; + + /** + * == drawForegroundColorGrid + * + * draws the foreground header and grid of swatch colors + */ + self.drawForegroundColorGrid = function(colors) { + var gridOffset, gridHeaderYOffset, gridHeaderXOffset, gridWidth; + + gridHeaderXOffset = 0; + gridHeaderYOffset = self.gridHeaderMargin; + gridOffset = self.gridHeaderFontSize + gridHeaderYOffset; + + self.drawGridHeader(self.fgGridHeaderText, gridHeaderXOffset, gridHeaderYOffset); + self.drawColorGrid(colors, gridOffset); + self.drawChosenForegroundValues('Typeface Color:', self.gridWidth, gridOffset); + }; + + /** + * == drawBackgroundColorGrid + * + * draws the background header and grid of swatch colors + */ + self.drawBackgroundColorGrid = function(colors) { + var gridOffset, gridHeaderYOffset, gridHeaderXOffset; + + gridHeaderXOffset = 0; + gridHeaderYOffset = self.fgGridHeight + self.gridGutter; + gridOffset = gridHeaderYOffset + self.gridHeaderMargin; + + self.drawGridHeader(self.bgGridHeaderText, gridHeaderXOffset, gridHeaderYOffset); + self.drawColorGrid(colors, gridOffset); + self.drawChosenBackgroundValues('Face Material:', self.gridWidth, gridOffset); + }; + + /** + * == drawGridHeader + * + * draws the grid's header + */ + self.drawGridHeader = function(text, xOffset, yOffset) { + var label = self.paper.text(xOffset + self.tileGutter, yOffset, text); + + // foreground fill for the score # + label.attr(self.fontAttrs).attr({'font-size': self.gridHeaderFontSize}); + }; + + /** + * == drawChosenForegroundValues + * + * draws placeholder text strings for the chosen foreground color's name + * and LRV values which can be later update through the .attr() methods + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenForegroundValues = function(titleText, xOffset, yOffset){ + // draw the box + self.drawChosenColorValues(titleText, xOffset, yOffset); + + // draw the text placeholders + self.fgColorNameText = self.paper.text(xOffset, yOffset + 50, '').attr(self.fontAttrs); + self.fgColorLRVText = self.paper.text(xOffset, yOffset + 110, '').attr(self.fontAttrs); + + // update the font size + self.fgColorNameText.attr({'font-size': self.textFontSize }); + self.fgColorLRVText.attr({'font-size': self.textFontSize * 1.1 }); + }; + + /** + * == drawChosenBackgroundValues + * + * draws placeholder text strings for the chosen background color's name + * and LRV values which can be later update through the .attr() methods + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenBackgroundValues = function(titleText, xOffset, yOffset){ + // draw the box + self.drawChosenColorValues(titleText, xOffset, yOffset); + + // draw the text placeholders + self.bgColorNameText = self.paper.text(xOffset, yOffset + 50, '').attr(self.fontAttrs); + self.bgColorLRVText = self.paper.text(xOffset, yOffset + 110, '').attr(self.fontAttrs); + + // update the font size + self.bgColorNameText.attr({'font-size': self.textFontSize }); + self.bgColorLRVText.attr({'font-size': self.textFontSize * 1.1 }); + }; + + + /** + * == drawChosenColorValues + * + * draws the containing box and titles for a chosen color's name and LRV value + * + * @param string titleText + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawChosenColorValues = function(titleText, xOffset, yOffset) { + var box, boxTitle, boxLrvTitle; + + // draw the containing box + box = self.paper.rect(xOffset - (self.gridGutter / 2), yOffset, self.boxWidth, self.boxHeight); + box.attr({ fill: '#f5f5f5', stroke: 'transparent' }); + box.glow({ width: 5, opacity: 0.3, color: "#ddd" }); + + // draw the titleText and LRV Value text strings + boxTitle = self.paper.text(xOffset, yOffset + 30, titleText).attr(self.fontAttrs); + boxLrvTitle = self.paper.text(xOffset, yOffset + 90, 'LRV Value:').attr(self.fontAttrs); + + boxTitle.attr({ 'font-size': self.textFontSize * 1.1 }); + boxLrvTitle.attr({ 'font-size': self.textFontSize * 1.1 }); + }; + + + /** + * == drawPreview + */ + self.drawPreview = function() { + var xOffset, yOffset, boxWidth, boxHeight, boxTitle; + + xOffset = self.gridWidth + self.boxWidth + (self.gridGutter * 2); + yOffset = self.gridHeaderMargin; + boxWidth = self.boxWidth + (self.tileHeight * 2); + boxHeight = boxWidth / 2; + + boxTitle = self.paper.text(xOffset, yOffset, 'Contrast Value:').attr(self.fontAttrs); + boxTitle.attr({'font-size': self.gridHeaderFontSize}); + + // draw the containing box + self.previewBox = self.paper.rect(xOffset, yOffset + self.gridHeaderFontSize, boxWidth, boxHeight); + self.previewBox.attr({ fill: '#f5f5f5', stroke: 'transparent' }); + self.previewBox.glow({ width: 5, opacity: 0.3, color: "#ddd" }); + + self.previewText = self.paper.text(xOffset + self.gridHeaderMargin + 60, yOffset + 110, '519'); + self.previewText.attr(self.fontAttrs); + self.previewText.attr({ 'font-size': self.gridHeaderFontSize * 5, 'font-weight': 'bold' }); + + self.contrastValueText = self.paper.text(xOffset + 180, yOffset, '').attr(self.fontAttrs); + self.contrastValueText.attr({'font-size': self.gridHeaderFontSize }); + + // move & stylize the icon indicator + self.contrastValueIcon = self.paper.path(self.uncheckedBox); + self.contrastValueIcon.translate(xOffset + 320, yOffset - 16); + self.contrastValueIcon.attr({ 'stroke': 'transparent', 'fill': "#ddd" }); + }; + + /** + * == drawColorGrid + * + * utility function responsible for solely drawing the grid by calculating + * the x and y offsets and passing that into the self.drawColorSwatch function + * + * @param array colors # array of javascript objects + * @param integer gridOffset # y-offset of where to begin drawing the grid + */ + self.drawColorGrid = function(colors, gridOffset) { + var xOffset, yOffset, rows; + + // split the array of colors into smaller arrays + // so we can draw rows of swatches + rows = self.chunk(colors, self.tilesPerRow); + + $.each(rows, function(i, row){ + $.each(row, function(j, color){ + xOffset = j * self.tileWidth + (j * self.tileGutter); + yOffset = i * self.tileHeight + (i * self.tileGutter) + gridOffset; + + self.drawColorSwatch(color, xOffset + self.tileGutter, yOffset); + }); + }); + }; + + /** + * == drawColorSwatch + * + * draws the actual color swatch at the given x and y offsets + * + * @param object color # Example: { "name": "Red", "hex": "cc3300", "value": 3 } + * @param integer xOffset + * @param integer yOffset + * @return Element + */ + self.drawColorSwatch = function(color, xOffset, yOffset) { + var swatch; + + // regular rectangle + swatch = self.paper.rect(xOffset, yOffset, self.tileWidth, self.tileHeight); + + // specify the swatch's fill, stroke, and opacity attributes + swatch.attr({ + "stroke": 'transparent', + "fill": "#" + color.hex + }); + + // add a slight drop shadow/glow effect instead of a stroke + swatch.glow({ width: 5, opacity: 0.3, color: "#aaa" }); + + swatch.data('color-name', color.name); + swatch.data('color-lrv', color.value); + swatch.data('color-hex', color.hex); + + if (color.category === 1) { + swatch.data('color-category', 'foreground'); + } else if (color.category === 2) { + swatch.data('color-category', 'background'); + } else{ + // do nothing + } + + /** + * click event + */ + swatch.click(function(){ + self.handleClickOrTouch(this); + }); + + swatch.touchstart(function(){ + self.handleClickOrTouch(this); + }); + + /** + * hover event + */ + $(swatch.node).hover( + // mouseover effect + function() { + swatch.g = swatch.glow({color: "#39c", width: 10, opacity: 0.5 }); + }, + // mouseout effect + function() { + swatch.g.remove(); + } + ); + }; + + self.handleClickOrTouch = function(colorSwatch) { + if (colorSwatch.data('color-category') === 'foreground') { + self.fgColorNameText.attr({ 'text': colorSwatch.data('color-name') }); + self.fgColorLRVText.attr({ 'text': colorSwatch.data('color-lrv') }); + self.previewText.attr({ 'fill': "#" + colorSwatch.data('color-hex') }); + self.previewText.data('lrv-value', colorSwatch.data('color-lrv')); + } + + if (colorSwatch.data('color-category') === 'background') { + self.bgColorNameText.attr({ 'text': colorSwatch.data('color-name') }); + self.bgColorLRVText.attr({ 'text': colorSwatch.data('color-lrv') }); + self.previewBox.attr({ 'fill': "#" + colorSwatch.data('color-hex') }); + self.previewBox.data('lrv-value', colorSwatch.data('color-lrv')); + } + + // update the LRV contrast value + self.updateContrastValue(); + }; + + /** + * update the contrast value with the percentage and message + */ + self.updateContrastValue = function() { + var lrvScore, lrvMessage, lrvColor; + + lrvScore = self.calculateContrastValue(); + + if (lrvScore >= self.adaMinContrastValue) { + lrvMessage = lrvScore + "%"; + lrvColor = 'green'; + + self.contrastValueIcon.attr({ 'path': self.checkedBox, 'fill': lrvColor }); + + } else if (lrvScore < self.adaMinContrastValue) { + lrvMessage = lrvScore + "%"; + lrvColor = 'red'; + + self.contrastValueIcon.attr({ 'path': self.uncheckedBox, 'fill': "#ddd" }); + + } else { + lrvMessage = ''; + self.contrastValueIcon.attr({ 'path': self.uncheckedBox, 'fill': "#ddd" }); + } + + self.contrastValueText.attr({ 'text': lrvMessage }); + }; + + + /** + * calculate the contrast value + */ + self.calculateContrastValue = function() { + var fgVal, bgVal, contrast, lrvScore, lrvValue; + + fgVal = self.previewText.data('lrv-value') * 1000; + bgVal = self.previewBox.data('lrv-value') * 1000; + + if (fgVal > bgVal) { + contrast = (bgVal / fgVal); + lrvValue = (contrast * 100) - 100; + lrvScore = lrvValue < 0 ? Math.round(lrvValue * -1) : Math.round(lrvValue); + } else if (fgVal < bgVal) { + contrast = (fgVal / bgVal); + lrvValue = (contrast * 100) - 100; + lrvScore = lrvValue < 0 ? Math.round(lrvValue * -1) : Math.round(lrvValue); + } else { + lrvScore = undefined; + } + + return lrvScore; + }; + + /** + * == chunk + * + * utility function to split an array into smaller arrays + * + * @see http://stackoverflow.com/a/11764168/633432 + */ + self.chunk = function(arr, len) { + var chunks = [], i = 0, n = arr.length; + + while (i < n) { + chunks.push(arr.slice(i, i += len)); + } + return chunks; + }; + + // finally, initialize our Color Contrast Calculator + self.init(); +} diff --git a/hard/color_contrast_calculator/index.html b/hard/color_contrast_calculator/index.html new file mode 100644 index 0000000..b140905 --- /dev/null +++ b/hard/color_contrast_calculator/index.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + ++ A few years ago we were tasked with creating a color contrast calculator for a store front to help customers comply with Americans with Disabilities Act (ADA). Over the years we've found that: +
+ We can address three of these four issues by porting the Flash application to Javascript (we'll leave the discussion of the client updating the colors for another day). For this advanced challenge, we'll be utilizing: +
+ Your job will be to write an object-oriented Javascript class that will render an interactive contrast calculator and render that output to the #output element below. The color data is provided to you as JSON within the data-color-values attribute of the div#colors element.
+
+{
+ "background": {
+ "0": { "name": "10234 Misty Blue", "value": "8", "hex": "727A8F", "category": 2 }
+ , "1": { "name": "10563 Metalic Silver", "value": "93", "hex": "bbbbbb", "category": 2 }
+ , "2": { "name": "13 Rose", "value": "6", "hex": "895D5E", "category": 2 }
+ , "3": { "name": "142 Steel Blue", "value": "11", "hex": "788DA2", "category": 2 }
+ , "4": { "name": "144 Dark Blue Jean", "value": "4", "hex": "2E3547", "category": 2 }
+ , "5": { "name": "15 Scandinavian Sky", "value": "14", "hex": "9498A1", "category": 2 }
+ , "6": { "name": "15451 Bristol Blue", "value": "11", "hex": "29309B", "category": 2 }
+ , "7": { "name": "166 Shell Beige", "value": "26", "hex": "C2B6B6", "category": 2 }
+ , "8": { "name": "167 Army Green", "value": "2", "hex": "40424F", "category": 2 }
+ , "9": { "name": "173 Hazy Green", "value": "5", "hex": "3E433F", "category": 2 }
+ , "10": { "name": "199 Yellow Cream", "value": "20", "hex": "0B0819", "category": 2 }
+ , "11": { "name": "20044 Brown Mustard", "value": "4", "hex": "60513C", "category": 2 }
+ , "12": { "name": "20060 Moss", "value": "5", "hex": "867B5D", "category": 2 }
+ , "13": { "name": "20126 Twiggy Brown", "value": "9", "hex": "877D73", "category": 2 }
+ , "14": { "name": "20134 Nugat Brown", "value": "4", "hex": "413630", "category": 2 }
+ , "15": { "name": "20177 Taupe", "value": "4", "hex": "5A4D47", "category": 2 }
+ , "16": { "name": "207 SW-Pine", "value": "6", "hex": "626753", "category": 2 }
+ , "17": { "name": "23003 Dusty Brown", "value": "17", "hex": "B3A797", "category": 2 }
+ , "18": { "name": "23013 Smokey Brown", "value": "10", "hex": "81674C", "category": 2 }
+ , "19": { "name": "24030 Earth Tan", "value": "8", "hex": "866A52", "category": 2 }
+ , "20": { "name": "24034 Stone Beige", "value": "20", "hex": "B9A992", "category": 2 }
+ , "21": { "name": "24714 Oakwood Brown", "value": "2", "hex": "63432C", "category": 2 }
+ , "22": { "name": "24735 Maroon Brown", "value": "1", "hex": "573C33", "category": 2 }
+ , "23": { "name": "24933 Cream", "value": "36", "hex": "D5BF90", "category": 2 }
+ , "24": { "name": "24937 Duranodic Brown", "value": "4", "hex": "332E2A", "category": 2 }
+ , "27": { "name": "252 Muddy Clay", "value": "4", "hex": "877D73", "category": 2 }
+ , "28": { "name": "258 Saddle Brown", "value": "2", "hex": "815634", "category": 2 }
+ , "29": { "name": "278 Light Tangerine", "value": "17", "hex": "D08242", "category": 2 }
+ , "30": { "name": "28363 Navy", "value": "7", "hex": "40424F", "category": 2 }
+ , "33": { "name": "285 Dusty Blue", "value": "1", "hex": "4A5362", "category": 2 }
+ , "34": { "name": "288 SW Ecru", "value": "29", "hex": "D0C3A1", "category": 2 }
+ , "38": { "name": "30026 Titanium Grey", "value": "19", "hex": "93979A", "category": 2 }
+ , "39": { "name": "3007 Neutral Grey", "value": "10", "hex": "736F6E", "category": 2 }
+ , "40": { "name": "30096 Gunmetal Grey", "value": "9", "hex": "595961", "category": 2 }
+ , "53": { "name": "32341 Dark Grey", "value": "1", "hex": "815634", "category": 2 }
+ , "55": { "name": "33127 Angora Grey", "value": "6", "hex": "626A6C", "category": 2 }
+ , "66": { "name": "40230 Dusty Olive", "value": "4", "hex": "515443", "category": 2 }
+ , "67": { "name": "407 Chinese Red", "value": "5", "hex": "A23016", "category": 2 }
+ , "68": { "name": "420 Straw", "value": "23", "hex": "BEB491", "category": 2 }
+ , "69": { "name": "440 Sunrise", "value": "24", "hex": "E2BC6B", "category": 2 }
+ , "70": { "name": "446 Steam", "value": "25", "hex": "BDCDDA", "category": 2 }
+ , "71": { "name": "44930 Retro Green", "value": "5", "hex": "6B6E3F", "category": 2 }
+ , "72": { "name": "45183 Dark Green", "value": "7", "hex": "1B331C", "category": 2 }
+ , "75": { "name": "50043 Aged Plum", "value": "4", "hex": "3C2C2D", "category": 2 }
+ , "76": { "name": "50075 Dusty Rose", "value": "5", "hex": "827273", "category": 2 }
+ , "77": { "name": "50951 Eggplant", "value": "4", "hex": "302341", "category": 2 }
+ , "78": { "name": "51 Medium Mahogany", "value": "4", "hex": "392E2A", "category": 2 }
+ , "79": { "name": "51051 Burgundy", "value": "4", "hex": "371A1E", "category": 2 }
+ , "80": { "name": "60972 Orange", "value": "16", "hex": "D26D35", "category": 2 }
+ , "81": { "name": "62 Baja Wood", "value": "20", "hex": "B4ABA6", "category": 2 }
+ , "82": { "name": "6341 Red Cent", "value": "8", "hex": "96543E", "category": 2 }
+ , "83": { "name": "70002 Carnival Red", "value": "2", "hex": "B71E20", "category": 2 }
+ , "84": { "name": "70253 Purple Dusk", "value": "4", "hex": "675C60", "category": 2 }
+ , "85": { "name": "71204 Deep Orchid", "value": "4", "hex": "382940", "category": 2 }
+ , "86": { "name": "80231 Apricot", "value": "13", "hex": "B07E3F", "category": 2 }
+ , "87": { "name": "82483 Yellow", "value": "53", "hex": "FFB900", "category": 2 }
+ , "88": { "name": "8991 Clay", "value": "7", "hex": "855950", "category": 2 }
+ , "89": { "name": "9013 Putnam Ivory", "value": "24", "hex": "d0bfa1", "category": 2 }
+ , "90": { "name": "91134 Alpine White", "value": "38", "hex": "ffffff", "category": 2 }
+ , "91": { "name": "91134 White", "value": "76", "hex": "ffffff", "category": 2 }
+ , "92": { "name": "91272 Light Beige", "value": "27", "hex": "CDC7BB", "category": 2 }
+ , "93": { "name": "93352 Bone White", "value": "30", "hex": "DCCBBB", "category": 2 }
+ , "94": { "name": "9414 Black", "value": "8", "hex": "000000", "category": 2 }
+ , "95": { "name": "BR-32 Brown", "value": "2", "hex": "67523F", "category": 2 }
+ }
+ , "foreground": {
+ "25": { "name": "24998 Yellow", "value": "53", "hex": "ffb900", "category": 1 }
+ , "26": { "name": "25001 Red", "value": "9", "hex": "fe0000", "category": 1 }
+ , "31": { "name": "28364 Silver Grey", "value": "59", "hex": "666054", "category": 1 }
+ , "32": { "name": "28383 Burgundy", "value": "6", "hex": "4B1201", "category": 1 }
+ , "35": { "name": "29931 Silver", "value": "85", "hex": "858585", "category": 1 }
+ , "36": { "name": "29932 Gold", "value": "77", "hex": "95671c", "category": 1 }
+ , "37": { "name": "29933 Teal", "value": "11", "hex": "1f6678", "category": 1 }
+ , "41": { "name": "311-214 Ash", "value": "74", "hex": "f0e8e5", "category": 1 }
+ , "42": { "name": "311-302 China Blue", "value": "15", "hex": "585c68", "category": 1 }
+ , "43": { "name": "311-305 Light Grey", "value": "68", "hex": "dadada", "category": 1 }
+ , "44": { "name": "311-306 Pearl Grey", "value": "49", "hex": "acaead", "category": 1 }
+ , "45": { "name": "311-307 Charcoal Grey", "value": "9", "hex": "454138", "category": 1 }
+ , "46": { "name": "311-398 Graphite", "value": "24", "hex": "636363", "category": 1 }
+ , "47": { "name": "311-801 Antique Ivory", "value": "70", "hex": "fbefd9", "category": 1 }
+ , "48": { "name": "311-903 Black Forrest Green", "value": "12", "hex": "3d4d4c", "category": 1 }
+ , "49": { "name": "31631 Brown", "value": "2", "hex": "4F392B", "category": 1 }
+ , "50": { "name": "31753 Salmon", "value": "54", "hex": "e8c4c8", "category": 1 }
+ , "51": { "name": "31898 Seafoam", "value": "39", "hex": "93c1bf", "category": 1 }
+ , "52": { "name": "32291 Rust", "value": "11", "hex": "8e4731", "category": 1 }
+ , "54": { "name": "32726 Tan", "value": "24", "hex": "958979", "category": 1 }
+ , "56": { "name": "37033 Cream", "value": "81", "hex": "FFFBF0", "category": 1 }
+ , "57": { "name": "37037 Black", "value": "8", "hex": "000000", "category": 1 }
+ , "58": { "name": "37042 White", "value": "76", "hex": "ffffff", "category": 1 }
+ , "59": { "name": "37047 Taupe", "value": "19", "hex": "847D6D", "category": 1 }
+ , "60": { "name": "37048 Azure Blue", "value": "8", "hex": "095285", "category": 1 }
+ , "61": { "name": "37050 Candlewick", "value": "46", "hex": "bfb6b1", "category": 1 }
+ , "62": { "name": "37058 Chocolate Brown", "value": "6", "hex": "342e22", "category": 1 }
+ , "63": { "name": "37060 Pine Green", "value": "10", "hex": "225d57", "category": 1 }
+ , "64": { "name": "37065 Slate", "value": "11", "hex": "484445", "category": 1 }
+ , "65": { "name": "37070 Almond", "value": "54", "hex": "ede2c4", "category": 1 }
+ , "73": { "name": "45960 Grass", "value": "32", "hex": "8ab798", "category": 1 }
+ , "74": { "name": "45964 Maui Blue", "value": "31", "hex": "81a5df", "category": 1 }
+ }
+}
+
+
+