diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4da0316 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +end_of_line = lf +insert_final_newline = true + +[*.md] +indent_size = 4 +trim_trailing_whitespace = false + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..2183d69 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "angulardoc.repoId": "a547aa17-a9ab-4f77-ba4c-f3167ae617d2", + "angulardoc.lastSync": 0 +} \ No newline at end of file diff --git a/exercises/01 - JavaScript Drum Kit/README.md b/exercises/01 - JavaScript Drum Kit/README.md index abe966a..5e39133 100644 --- a/exercises/01 - JavaScript Drum Kit/README.md +++ b/exercises/01 - JavaScript Drum Kit/README.md @@ -1,13 +1,13 @@ # Exercise 1: JavaScript Drum Kit Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 9, 2016 +Last Commit Date: May 12, 2017 An HTML page displays a collection of `div` elements, each containing a letter that corresponds with a key on the keyboard, and the name of the soundclip to be played when that button is clicked. When a user presses a key that matches - one of the `div` elements, the page should play the corresponding soundclip - and place a temporary 'highlight' (or border) around the `div`. Write the - JavaScript code necessary to add this functionality. + one of the letters displayed in the `div` elements, the page should play + the corresponding soundclip and place a temporary 'highlight' (or border) + around the `div`. Write the JavaScript code necessary to add this functionality. ## Guide @@ -17,11 +17,11 @@ We are provided with the HTML, CSS, and sound clips necessary to create this - HTML `data-*` attributes: Introduced in HTML5, `data-*` attributes (where * can be anything you want) allow us to store _custom data_ on any HTML element. Each - `div.key` and `audio` element in the provided HTML file has a `data-key` attribute - which corresponds with a keyboard button. + `div.key` (`
`) and `audio` element in the + provided HTML file has a `data-key` attribute which corresponds with a keyboard button. -- CSS `playing` class & pre-defined style: The provided CSS file already has an `playing` - class defined with some styling in it. We will apply this class to the correct +- CSS `playing` class & pre-defined style: The provided CSS file already has a `playing` + class defined with some rules in it. We will apply this class to the correct element, depending on the key pressed by the user, and remove it once animation is finished. diff --git a/exercises/01 - JavaScript Drum Kit/index.html b/exercises/01 - JavaScript Drum Kit/index.html index 38a4ee2..cc3c007 100644 --- a/exercises/01 - JavaScript Drum Kit/index.html +++ b/exercises/01 - JavaScript Drum Kit/index.html @@ -65,29 +65,46 @@ * the keypress, add a class to the specific element that matches with the keypress, * and then remove that class in order to reset the element to it's original state. */ - function playSound(e) { - const soundclip = document.querySelector(`audio[data-key="${e.keyCode}"]`); - const keyelement = document.querySelector(`.key[data-key="${e.keyCode}"]`); - if (!soundclip) return; // Stop function from running if key pressed doesn't match up with our elements + (()=> { + const playSound = (e) => { + const soundclip = document.querySelector(`audio[data-key="${e.keyCode}"]`); + const keyelement = document.querySelector(`.key[data-key="${e.keyCode}"]`); - keyelement.classList.add('playing'); + if (!soundclip) return undefined; // Stop function from running if key pressed doesn't match up with our elements - soundclip.currentTime = 0; // Play sound clip from start every time a corresponding key is pressed - soundclip.play(); - } + keyelement.classList.add('playing'); - function removeTransition(e) { - if (e.propertyName !== 'transform') return; // skip if it's not a transform event - this.classList.remove('playing'); - } + // Ensures that the sound clip always plays from the beginning. Otherwise, + // if the 'a' key is pressed twice rapidly, the soundclip will only play through + // once. + soundclip.currentTime = 0; - const keys = document.querySelectorAll('.key'); // Find all elements in the document with a class 'key' - keys.forEach(key => key.addEventListener('transitionend', removeTransition)); + soundclip.play(); // Play sound + } - window.addEventListener('keydown', playSound); + const removeTransition = (e) => { + // skip if it's not a transform event + if (e.propertyName !== 'transform') return undefined; + e.target.classList.remove('playing'); + } + + // Find all elements in the document with a class 'key' + const keys = document.querySelectorAll('.key'); + + // Listen for any `keydown` events that occur on this browser window instance (this page) + // When a `keydown` event is observered, trigger the `playSound` function, passing in the + // `keydown` event as the argument (e) + window.addEventListener('keydown', playSound); + + keys.forEach(key => + key.addEventListener( + 'transitionend', + (e) => removeTransition.call(key, e) + )); + })(); - \ No newline at end of file + diff --git a/exercises/02 - JS + CSS Clock/README.md b/exercises/02 - JS + CSS Clock/README.md index 9df65f1..a0c442c 100644 --- a/exercises/02 - JS + CSS Clock/README.md +++ b/exercises/02 - JS + CSS Clock/README.md @@ -1,44 +1,101 @@ # Exercise 2: JS + CSS Clock -Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 9, 2016 -Given an web page with an analog clock created out of CSS, update the CSS - and write the JavaScript necessary to make the clock functional. +> Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) +> Last Commit Date: May 12, 2017 + +Given a web page with an analog clock created with CSS, write the + JavaScript necessary to make the clock functional. Make alterations to the CSS + as necessary. ## Guide The HTML file has 3 `div` elements which correspond with the second, minute, and - hour hand on a clock. We'll create references to these elements and dynamically - update certain CSS properties to change their positions so they reflect the - current time. Easy peasy. + hour hand on a clock + +```html + +
+
+
+ +``` + +The necessary JavaScript code shouldn't be too crazy; + we'll create references to these elements and dynamically + update certain CSS properties to change their positions so they reflect the + current time. Easy peasy. **Steps:** -- CSS: - - 1. Set the `transform-origin` CSS property of the `.hand` class at 100%; the default - value is 50% (or the midway point of the HTML element), but if we leave it there - the clock hands will tranform from their individal centers as opposed to the - center of the clock. Changing the value to 100% shifts the _origin point of the - transformations_ to the furthest x-axis point of the HTML element. - 2. The hands are all laying flat; we need them to be vertical. Rotate all of the - hands by 90 degrees so that they are upright. - 3. Set the `transition` CSS property of `.hand` to `all 0.05s`; this tells the browser - to gradually apply any changes to the element's styling over a 0.05 second period. - 4. Set the `transition-timing-function` CSS property of `.hand` to whatever function - you prefer, or define your own using the `cubic-bezier()` property value. - -- JavaScript - - 1. Declare & define variables for each clock hand and reference the corresponding _HTML - element_. - 2. Create a function which will be responsible for updating the position of all the - clock hands. - - Calculate the necessary rotation using the _current numerical time value_ for each hand - and dividing it by the max value possible to get the percentage, multiplying the result - of that by 360 (each hand can rotate 360 degrees) to get the numerical value for the - rotation, and increasing that by another 90 degrees to compensate for the shift - originally applied by the CSS styling on page load. - 3. Call the function defined in step 2 every second. +- **CSS**: + + 1. The hands are all laying flat; we need them to be vertical. Rotate all of the + hands by 90 degrees so that they are upright by giving the `.hand` class a + `transform` rule with the value `rotate(90deg)`. + + 1. Set the `transform-origin` CSS property of the `.hand` class to `100%`; the default + value is `50%` (or the midway point of the HTML element), but if we leave it there + the clock hands will transform from the respective centers of their lines as opposed to the + center of the clock. (If that doesn't make sense, try it out in your code. Set the value for + `transform-origin` rule completely and check again. Finally, try it again with `50%`.). + Changing the value to 100% shifts the _point of origin for the transformation_ + to the furthest point on the x-axis of the HTML element. + + 1. Set the `transition` CSS property of `.hand` to `all 0.05s`; this tells the browser + to gradually apply any changes to the element's styling over a 0.05 second period. + + 1. Set the `transition-timing-function` CSS property of `.hand` to whatever function + you prefer, or define your own using the `cubic-bezier()` property value. + +- **JavaScript**: + + 1. Declare & define variables for each clock hand and reference the corresponding _HTML + element_. + + EX: `const secondHand = document.querySelector('.second-hand');` + + 1. Create a function which will be responsible for calculating the number of degrees that we need + to rotate each clock hand by. It should accept two arguments: the _current numerical value_ of the + clock hand, and the max value possible of the clock hand (if you want the number of degrees needed for + the second hand and the current time is 03:15:18, you would pass in (18, 60) where 18 is the current + value of the second hand, and 60 is the maximum possible value). + + - Divide the current numerical value of the clock hand by it's max possible value to get the rotation as + a percentage, then multiply the result of that by 360 (each hand can rotate 360 degrees) to convert + the value from a percentage to an integer, and increase that result by another 90 degrees to compensate + for the shift originally applied by the CSS styling on page load. + + ```javascript + const calcDegrees = (time, max) => ((time / max) * 360) + 90; + ``` + + 1. Create a function that will automatically run every second; in the body of the function, + create a variable and define it as a new Date object. Then, create three variables which will + hold references to the rotation amount to be applied to each clock hand. To get the rotation amount, + define the variables as the return value from calling the `calcDegrees` function; each call should + pass in the correct values in relation to whichever clock hand they are supposed to represent. + + 1. Still within the body of the function from step 3, update the `transform` rule for each + clock hand to their corresponding updated values. + + ```javascript + /* Steps 3 & 4 */ + + // Call function once every second + setInterval(() => { + // Create new Date object + const now = new Date(); + // Get current seconds, minutes, & hours and calculate the degree shift + const + secondHandDegrees = calcDegrees(now.getSeconds(), 60), + minuteHandDegrees = calcDegrees(now.getMinutes(), 60), + hourHandDegrees = calcDegrees(now.getHours(), 12); + // Apply rotation to the clock hands corresponding with current time value + secondHand.style.transform = `rotate(${secondHandDegrees}deg)`; + minuteHand.style.transform = `rotate(${minuteHandDegrees}deg)`; + hourHand.style.transform = `rotate(${hourHandDegrees}deg)`; + }, 1000); // 1000ms === 1s + + ``` Yaaaaaay! All done! diff --git a/exercises/02 - JS + CSS Clock/index.html b/exercises/02 - JS + CSS Clock/index.html index 907a500..bd99970 100644 --- a/exercises/02 - JS + CSS Clock/index.html +++ b/exercises/02 - JS + CSS Clock/index.html @@ -19,17 +19,17 @@ - + // Create references to the HTML elements that we want to transform + (()=> { + const + secondHand = document.querySelector('.second-hand'), + minuteHand = document.querySelector('.min-hand'), + hourHand = document.querySelector('.hour-hand') + + // Helper function responsible for calculating the amount to rotate a hand + const calcDegrees = (time, max) => ((time / max) * 360) + 90; + // Call function once every second + setInterval(() => { + + // Create new Date object + const now = new Date(); + + // Get current seconds, minutes, & hours and calculate the degree shift + const + secondHandDegrees = calcDegrees(now.getSeconds(), 60), + minuteHandDegrees = calcDegrees(now.getMinutes(), 60), + hourHandDegrees = calcDegrees(now.getHours(), 12); + + // Apply rotation to the clock hands corresponding with current time value + secondHand.style.transform = `rotate(${secondHandDegrees}deg)`; + minuteHand.style.transform = `rotate(${minuteHandDegrees}deg)`; + hourHand.style.transform = `rotate(${hourHandDegrees}deg)`; + }, 1000); + })(); + - \ No newline at end of file + diff --git a/exercises/03 - CSS Variables/README.md b/exercises/03 - CSS Variables/README.md index 222c3d2..7a35a35 100644 --- a/exercises/03 - CSS Variables/README.md +++ b/exercises/03 - CSS Variables/README.md @@ -1,10 +1,11 @@ # Exercise 3: CSS Variables + Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 10, 2016 +Last Commit Date: May 12, 2017 The web page provided in this exercise displays an image, and has 3 form inputs from which the user can manipulate the padding, blur amount, and background - color of the image. Update the CSS and write the JavaScript code necessary to + color of the image. Update the CSS and write the JavaScript code necessary to bring functionality to the inputs. ## Guide @@ -24,6 +25,7 @@ The purpose of this exercise is to gain experience using _CSS3 variables_. These **Steps:** - CSS: + 1. Declare a new style for the `:root` element and declare three variables inside the style definition for `:root` with the same names as the `input` _HTML elements_. _CSS3 variables_ are declared in the following syntax format: @@ -36,7 +38,8 @@ The purpose of this exercise is to gain experience using _CSS3 variables_. These --padding: 10px; } ``` - 2. Declare a new style for the `img` element and set the `background`, `filter`, and + + 1. Declare a new style for the `img` element and set the `background`, `filter`, and `padding` properties to the variables we defined at the root element: ```CSS /* 'var(--variableName)' to use previously defined CSS properties */ @@ -47,21 +50,26 @@ The purpose of this exercise is to gain experience using _CSS3 variables_. These padding: var(--padding); } ``` - 3. Declare a new style for the `.hl` class and set the color to the `base` variable. + + 1. Declare a new style for the `.hl` class and set the color to the `base` variable. - JavaScript: + 1. Declare & define a variable as a reference to all of the inputs on the page. - 2. Iterate through the _HTML Node Elements_ that the variable is referencing and - attach _event listeners_ to all of them that will call on an _event handler_ whenever - the input value has been changed. - 3. Repeat step 2, listening for mouse movements on the inputs instead of value - changes. - 4. Define a function that will be used as the _event handler_. This will update - the value of the _CSS3 variable_ **at the document level** corresponding with the - `input` element's `name` property which triggered the event handler. - - Minor 'gotcha': Properties like `padding` and `blur` won't update because + + 1. Iterate through the _HTML Node Elements_ that the variable is referencing and + attach _event listeners_ to each one that will call on an _event handler_ whenever + the input value has been changed (the `change` event). + + 1. Repeat step 2, listening for mouse movements on the inputs instead of value + changes (the `mousemove` event). + + 1. Define a function that will be used as the _event handler_. It will update + the value of the _CSS3 variable_ **at the root document level** corresponding with + the `name` property of the `input` element which called this function. + - Minor 'gotcha': Properties like `padding` and `blur` won't update because the value from the input does not include the type of measurement we are using - ('px', 'em', etc.). The `input` _HTML elements_ also have a `data-*` property if + ('px', 'em', etc.). The `input` _HTML elements_ also have a `data-sizing` property if they require a suffix. We can use this to attach the correct suffix to the value if necessary. diff --git a/exercises/03 - CSS Variables/index.html b/exercises/03 - CSS Variables/index.html index b21e1ab..d422ba0 100644 --- a/exercises/03 - CSS Variables/index.html +++ b/exercises/03 - CSS Variables/index.html @@ -1,29 +1,26 @@ - Scoped CSS Variables and JS - -

Update CSS Variables with JS

@@ -64,26 +60,43 @@

Update CSS Variables with JS

- + - - - \ No newline at end of file + diff --git a/exercises/04 - Array Cardio Day 1/README.md b/exercises/04 - Array Cardio Day 1/README.md index b659616..584f0c5 100644 --- a/exercises/04 - Array Cardio Day 1/README.md +++ b/exercises/04 - Array Cardio Day 1/README.md @@ -1,6 +1,6 @@ # Exercise 4: Array Cardio Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 12, 2016 +Last Commit Date: May 12, 2017 Not really much of a guide necessary for this one. The challenge is pretty well documented as far as what's expected from the developer; use diff --git a/exercises/04 - Array Cardio Day 1/index.html b/exercises/04 - Array Cardio Day 1/index.html index 7a44706..b7bcaf7 100644 --- a/exercises/04 - Array Cardio Day 1/index.html +++ b/exercises/04 - Array Cardio Day 1/index.html @@ -8,6 +8,7 @@ - \ No newline at end of file + diff --git a/exercises/05 - Flex Panel Gallery/README.md b/exercises/05 - Flex Panel Gallery/README.md index 6dc7d76..854c309 100644 --- a/exercises/05 - Flex Panel Gallery/README.md +++ b/exercises/05 - Flex Panel Gallery/README.md @@ -1,6 +1,6 @@ # Exercise 5: Flex Panel Gallery Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 12, 2016 +Last Commit Date: May 12, 2017 We are given a web page with five `div` HTML elements with a class `panels`, each containing three `p` HTML elements with some text. These five `div` elements diff --git a/exercises/05 - Flex Panel Gallery/index.html b/exercises/05 - Flex Panel Gallery/index.html index 7aa0b83..80e4ac1 100644 --- a/exercises/05 - Flex Panel Gallery/index.html +++ b/exercises/05 - Flex Panel Gallery/index.html @@ -1,6 +1,5 @@ - Flex Panels 💪 @@ -27,29 +26,26 @@ .panel1 { background-image: url(https://source.unsplash.com/gYl-UtwNg_I/1500x1500); } - + .panel2 { background-image: url(https://source.unsplash.com/1CD3fd8kHnE/1500x1500); } - + .panel3 { background-image: url(https://images.unsplash.com/photo-1465188162913-8fb5709d6d57?ixlib=rb-0.3.5&q=80&fm=jpg&crop=faces&cs=tinysrgb&w=1500&h=1500&fit=crop&s=967e8a713a4e395260793fc8c802901d); } - + .panel4 { background-image: url(https://source.unsplash.com/ITjiVXcwVng/1500x1500); } - + .panel5 { background-image: url(https://source.unsplash.com/3MNzGlQM7qs/1500x1500); } - - -

Hey

@@ -81,20 +77,18 @@ - - - - - \ No newline at end of file + diff --git a/exercises/06 - Type Ahead/README.md b/exercises/06 - Type Ahead/README.md index 40d930f..8005fbc 100644 --- a/exercises/06 - Type Ahead/README.md +++ b/exercises/06 - Type Ahead/README.md @@ -1,6 +1,6 @@ # Exercise 6: Type Ahead AJAX Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 12, 2016 +Last Commit Date: May 12, 2017 We are given a web page with an `input` HTML element in which the user can insert text, and an `unordered list` below that `input` which will display cities & states diff --git a/exercises/06 - Type Ahead/index.html b/exercises/06 - Type Ahead/index.html index 75cd271..5753c51 100644 --- a/exercises/06 - Type Ahead/index.html +++ b/exercises/06 - Type Ahead/index.html @@ -17,52 +17,48 @@ - \ No newline at end of file + diff --git a/exercises/07 - Array Cardio Day 2/README.md b/exercises/07 - Array Cardio Day 2/README.md index 786100a..0360005 100644 --- a/exercises/07 - Array Cardio Day 2/README.md +++ b/exercises/07 - Array Cardio Day 2/README.md @@ -1,6 +1,6 @@ # Exercise 7: Array Cardio Day 2 Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 12, 2016 +Last Commit Date: May 12, 2017 More fun with Array methods! Much like the previous Array Cardio exercise, the requirements are pretty well documented. This exercise utilizes the following diff --git a/exercises/07 - Array Cardio Day 2/index.html b/exercises/07 - Array Cardio Day 2/index.html index a8ee84c..50e4385 100644 --- a/exercises/07 - Array Cardio Day 2/index.html +++ b/exercises/07 - Array Cardio Day 2/index.html @@ -25,32 +25,33 @@ { text: 'Nice Nice Nice!', id: 542328 } ]; + const yr = new Date().getFullYear(); // Some and Every Checks - // Array.prototype.some() + // Array.prototype.some() // is at least one person 19? - const isAdult = people.some(person => ((new Date()).getFullYear()) - person.year >= 19); + const isAdult = people.some(({year}) => yr - year >= 19); console.log({ isAdult }); // Array.prototype.every() // is everyone 19? - const allAdults = people.every(person => ((new Date()).getFullYear()) - person.year >= 19); + const allAdults = people.every(({year}) => yr - year >= 19); console.log({ allAdults }); // Array.prototype.find() // Find is like filter, but instead returns just the one you are looking for // find the comment with the ID of 823423 - const comment = comments.find(comment => comment.id === 823423); + const comment = comments.find(({id}) => id === 823423); console.log(comment); // Array.prototype.findIndex() // Find the comment with this ID 823423 and delete it - const index = comments.findIndex(comment => comment.id === 823423); + const index = comments.findIndex(({id}) => id === 823423); const newComments = [ ...comments.slice(0, index), ...comments.slice(index + 1) ]; - console.log(newComments) + console.table(newComments) - \ No newline at end of file + diff --git a/exercises/08 - Fun with HTML5 Canvas/README.md b/exercises/08 - Fun with HTML5 Canvas/README.md index c1192d4..9e737a7 100644 --- a/exercises/08 - Fun with HTML5 Canvas/README.md +++ b/exercises/08 - Fun with HTML5 Canvas/README.md @@ -1,6 +1,6 @@ # Exercise 8: Fun With HTML5 Canvas Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 14, 2016 +Last Commit Date: May 12, 2017 We're given an HTML page with a `canvas` element in which the user should be able to click and drag their mouse to draw. When the user clicks+drags their mouse, diff --git a/exercises/08 - Fun with HTML5 Canvas/index.html b/exercises/08 - Fun with HTML5 Canvas/index.html index d54107b..354589f 100644 --- a/exercises/08 - Fun with HTML5 Canvas/index.html +++ b/exercises/08 - Fun with HTML5 Canvas/index.html @@ -15,6 +15,7 @@ - \ No newline at end of file + diff --git a/exercises/09 - Dev Tools Domination/README.md b/exercises/09 - Dev Tools Domination/README.md index deda385..804131b 100644 --- a/exercises/09 - Dev Tools Domination/README.md +++ b/exercises/09 - Dev Tools Domination/README.md @@ -1,6 +1,6 @@ # Exercise 9: Dev Tools Domination Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 15, 2016 +Last Commit Date: May 12, 2017 This is a simple dev tools exercise. We'll explore how to set _break points_ in the browser debugger, and learn about various `console` methods that allow us diff --git a/exercises/10 - Hold Shift and Check Checkboxes/README.md b/exercises/10 - Hold Shift and Check Checkboxes/README.md index 352ddc5..1db7afe 100644 --- a/exercises/10 - Hold Shift and Check Checkboxes/README.md +++ b/exercises/10 - Hold Shift and Check Checkboxes/README.md @@ -1,6 +1,6 @@ # Exercise 10: Hold Shift and Check Checkboxes Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 15, 2016 +Last Commit Date: May 12, 2017 We're given an HTML page that displays a collection of `input` HTML elements of type `checkbox`, each followed by a `p` HTML element that will have it's diff --git a/exercises/10 - Hold Shift and Check Checkboxes/index.html b/exercises/10 - Hold Shift and Check Checkboxes/index.html index 9b2a3ff..27975cb 100644 --- a/exercises/10 - Hold Shift and Check Checkboxes/index.html +++ b/exercises/10 - Hold Shift and Check Checkboxes/index.html @@ -60,7 +60,7 @@
@@ -105,43 +105,52 @@ - \ No newline at end of file + diff --git a/exercises/11 - Custom Video Player/README.md b/exercises/11 - Custom Video Player/README.md index a9e510a..5cfe96f 100644 --- a/exercises/11 - Custom Video Player/README.md +++ b/exercises/11 - Custom Video Player/README.md @@ -1,6 +1,6 @@ # Exercise 11: Custom Video Player Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 17, 2016 +Last Commit Date: May 12, 2017 When the HTML page is loaded in a browser, it displays a video player with controls for playing/pausing the video, scrolling through the video progress, skipping/ diff --git a/exercises/11 - Custom Video Player/scripts.js b/exercises/11 - Custom Video Player/scripts.js index 5f66391..8ff9f58 100644 --- a/exercises/11 - Custom Video Player/scripts.js +++ b/exercises/11 - Custom Video Player/scripts.js @@ -1,36 +1,50 @@ +"use strict"; (() => { - const player = document.querySelector('.player'), - video = player.querySelector('.viewer'), - progress = player.querySelector('.progress'), - progressBar = player.querySelector('.progress__filled'), - toggle = player.querySelector('.toggle'), - skipButtons = player.querySelectorAll('[data-skip]'), - ranges = player.querySelectorAll('.player__slider') + const player = document.querySelector(".player"), + video = player.querySelector(".viewer"), + progress = player.querySelector(".progress"), + progressBar = player.querySelector(".progress__filled"), + toggle = player.querySelector(".toggle"), + skipButtons = player.querySelectorAll("[data-skip]"), + ranges = player.querySelectorAll(".player__slider"); - let togglePlay = () => video[video.paused ? 'play' : 'pause'](), - updateButton = () => toggle.textContent = video.paused ? '►' : '❚ ❚', - handleProgress = () => progressBar.style.flexBasis = `${(video.currentTime / video.duration) * 100}%`, - scrub = (e) => video.currentTime = ((e.offsetX / progress.offsetWidth) * video.duration) + const togglePlay = () => video[video.paused ? "play" : "pause"](), + updateButton = () => toggle.textContent = video.paused ? "►" : "❚ ❚", + handleProgress = () => + progressBar.style.flexBasis = `${video.currentTime / video.duration * 100}%`, + scrub = e => + video.currentTime = e.offsetX / progress.offsetWidth * video.duration, + progressMoved = e => mousedown && scrub(e), + progressUp = e => mousedown = false, + progressDown = e => mousedown = true, + bClick = b => video.currentTime += parseFloat(b.dataset.skip), + updateRange = (range, e) => video[range.name] = range.value; - video.addEventListener('click', togglePlay) - video.addEventListener('play', updateButton) - video.addEventListener('pause', updateButton) - video.addEventListener('timeupdate', handleProgress) + let mousedown = false; - toggle.addEventListener('click', togglePlay) + const events = [ + { event: "click", handler: togglePlay, target: video }, + { event: "play", handler: updateButton, target: video }, + { event: "pause", handler: updateButton, target: video }, + { event: "timeupdate", handler: handleProgress, target: video }, + { event: "click", handler: togglePlay, target: toggle }, + { event: "click", handler: scrub, target: progress }, + { event: "mousedown", handler: progressDown, target: progress }, + { event: "mousemove", handler: progressMoved, target: progress }, + { event: "mouseup", handler: progressUp, target: progress }, + { event: "click", handler: bClick, target: skipButtons }, + { event: ["change", "mousemove"], handler: updateRange, target: ranges } + ]; - let mousedown = false - progress.addEventListener('click', scrub) - progress.addEventListener('mousemove', (e) => mousedown && scrub(e)) - progress.addEventListener('mousedown', () => mousedown = true) - progress.addEventListener('mouseup', () => mousedown = false) - - skipButtons.forEach(button => { - button.addEventListener('click', () => video.currentTime += parseFloat(button.dataset.skip)) - }) - - ranges.forEach(range => { - range.addEventListener('change', () => video[range.name] = range.value) - range.addEventListener('mousemove', () => video[range.name] = range.value) - }) + events.forEach( + ({ event: e, handler: h, target: t }) => + (t instanceof NodeList + ? t.forEach((el, i) => { + el.addEventListener( + typeof e === "string" ? e : e[i], + typeof h === "function" ? h.bind(null, el) : h[i].bind(null, el) + ); + }) + : t.addEventListener(e, h)) + ); })(); diff --git a/exercises/12 - Key Sequence Detection/README.md b/exercises/12 - Key Sequence Detection/README.md index 4fe1f48..505af56 100644 --- a/exercises/12 - Key Sequence Detection/README.md +++ b/exercises/12 - Key Sequence Detection/README.md @@ -1,6 +1,6 @@ # Exercise 12: Key Sequence Detection Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 18, 2016 +Last Commit Date: May 12, 2017 We're given an HTML document with...basically nothing. There's a `script` tag in the document header that loads a JavaScript file from [Cornify.com](https://www.cornify.com) diff --git a/exercises/12 - Key Sequence Detection/index.html b/exercises/12 - Key Sequence Detection/index.html index e9d7a0b..1165a62 100644 --- a/exercises/12 - Key Sequence Detection/index.html +++ b/exercises/12 - Key Sequence Detection/index.html @@ -11,7 +11,8 @@ - \ No newline at end of file + diff --git a/exercises/13 - Slide in on Scroll/README.md b/exercises/13 - Slide in on Scroll/README.md index 73e739b..0669658 100644 --- a/exercises/13 - Slide in on Scroll/README.md +++ b/exercises/13 - Slide in on Scroll/README.md @@ -1,6 +1,6 @@ # Exercise 13: Slide In On Scroll Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 19, 2016 +Last Commit Date: May 12, 2017 Given an HTML document with multiple paragraphs and images, write the necessary JavaScript code to slide the images into view when the user scrolls to a point diff --git a/exercises/13 - Slide in on Scroll/index.html b/exercises/13 - Slide in on Scroll/index.html index c872b99..61daf57 100644 --- a/exercises/13 - Slide in on Scroll/index.html +++ b/exercises/13 - Slide in on Scroll/index.html @@ -139,18 +139,20 @@

Slide in on Scroll

(() => { const sliderImages = document.querySelectorAll('.slide-in'); - function debounce(func, wait = 20, immediate = true) { + const debounce = (func, wait = 20, immediate = true) => { let timeout; - return function () { - const context = this, args = arguments; - const later = function () { + + return (...args)=> { + const later = () => { timeout = null; - if (!immediate) func.apply(context, args); + if (!immediate) func.apply(this, args); }; + const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); + + if (callNow) func.apply(this, args); }; }; @@ -229,4 +231,4 @@

Slide in on Scroll

- \ No newline at end of file + diff --git a/exercises/14 - JavaScript References VS Copying/README.md b/exercises/14 - JavaScript References VS Copying/README.md index af92fdf..2c4c064 100644 --- a/exercises/14 - JavaScript References VS Copying/README.md +++ b/exercises/14 - JavaScript References VS Copying/README.md @@ -1,6 +1,6 @@ # Exercise 14: JavaScript Reference vs Copying Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 19, 2016 +Last Commit Date: May 12, 2017 No guide necessary! We're learning about JavaScript variable referencing vs. copying. If you want a full-blown explanation, take a look at [chapter 11, section diff --git a/exercises/15 - LocalStorage/README.md b/exercises/15 - LocalStorage/README.md index de9e4f0..e177189 100644 --- a/exercises/15 - LocalStorage/README.md +++ b/exercises/15 - LocalStorage/README.md @@ -1,6 +1,6 @@ # Exercise 15: LocalStorage Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 19, 2016 +Last Commit Date: May 12, 2017 The web page simulates a restaurant's menu. The user should be able to add new dishes to the list using the `form` HTML element without having diff --git a/exercises/16 - Mouse Move Shadow/README.md b/exercises/16 - Mouse Move Shadow/README.md index 2879e01..8cc4784 100644 --- a/exercises/16 - Mouse Move Shadow/README.md +++ b/exercises/16 - Mouse Move Shadow/README.md @@ -1,6 +1,6 @@ # Exercise 16: Mouse Move Shadow Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 23, 2016 +Last Commit Date: May 12, 2017 We're given an HTML document with a `div` element containing an `h1` element. The `h1` element has a `textShadow` _style property_ which we want to manipulate diff --git a/exercises/17 - Sort Without Articles/README.md b/exercises/17 - Sort Without Articles/README.md index 0b57c38..f38f09e 100644 --- a/exercises/17 - Sort Without Articles/README.md +++ b/exercises/17 - Sort Without Articles/README.md @@ -1,6 +1,6 @@ # Exercise 17: Sort Without Articles Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 23, 2016 +Last Commit Date: May 12, 2017 We're given an HTML page with an _unordered list_, and an _array of string values_ in the `script` tag. Sort the values in the array **excluding diff --git a/exercises/17 - Sort Without Articles/index.html b/exercises/17 - Sort Without Articles/index.html index 7274fce..dc54ee2 100644 --- a/exercises/17 - Sort Without Articles/index.html +++ b/exercises/17 - Sort Without Articles/index.html @@ -77,4 +77,4 @@ - \ No newline at end of file + diff --git a/exercises/18 - Adding Up Times with Reduce/README.md b/exercises/18 - Adding Up Times with Reduce/README.md index af9108d..df0190f 100644 --- a/exercises/18 - Adding Up Times with Reduce/README.md +++ b/exercises/18 - Adding Up Times with Reduce/README.md @@ -1,6 +1,6 @@ # Exercise 18: Adding Up Times With Reduce Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) -Last Commit Date: Dec 24, 2016 +Last Commit Date: May 12, 2017 The HTML document contains an _unordered list_ with multiple _list items_, each with a `data-time` which reflect a time in minutes and seconds. Our goal is to diff --git a/exercises/18 - Adding Up Times with Reduce/index.html b/exercises/18 - Adding Up Times with Reduce/index.html index 6af08d8..673e96c 100644 --- a/exercises/18 - Adding Up Times with Reduce/index.html +++ b/exercises/18 - Adding Up Times with Reduce/index.html @@ -186,7 +186,7 @@ - \ No newline at end of file + diff --git a/exercises/19 - Webcam Fun/README.md b/exercises/19 - Webcam Fun/README.md new file mode 100644 index 0000000..305da3a --- /dev/null +++ b/exercises/19 - Webcam Fun/README.md @@ -0,0 +1,237 @@ +# Exercise 19: Webcam Fun +Nitish Dayal, Software & Applications Developer - [Contact](http://nitishdayal.me) +Last Commit Date: May 12, 2017 + +We're given an HTML page with a button labeled 'Take Photo' which calls upon a `takePhoto()` + function on a `click` event, a collection of `input` elements of type `range` with RGB min/max + labels, a `canvas` element, a `video` element, and an empty div with the class `strip`. Our goal + is to write the necessary JavaScript code to ask permission for the user's webcam, display the + feed from that webcam on the page, allow the user to save pictures that are displayed, + and allow the user to alter the image using the RGB sliders. + +## Guide + +This challenge will require use of the `Navigator` _Web API_ ([MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/Navigator)), + the `CanvasRenderingContext2D` _Web API_ ([MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D), + and the `MediaDevices` _Web API_ ([MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/mediaDevices)). + If you're not a fan of reading documentation, here's a simple overview: + + - The `Navigator` interface is a representation of the application in which the JavaScript + code is running (in most cases, the browser) + - The `MediaDevices` interface provides a way to access the user's connected media hardware, + such as a webcam or microphone by using the `getUserMedia` method. The method takes + an object as an argument which specifies the media items the program needs access to; + in our case, the webcam. + +The `scripts.js` file already has some `constants` defined as references: a reference to + the `video` element, the `canvas` element, the `canvas` context, to the `div` element + where we'll display any photos the user has taken, and a reference to the `audio` element + which uses [this](http://wesbos.com/demos/photobooth/snap.mp3) file as it's source. + +We begin by using the navigator web API in combination with the mediaDevices web API to + request permission from the user to access their webcam; this request returns a _promise_ + with the resulting `MediaStream` object or the rejected promise with an error message. **Note: + This promise is only resolved *IF* the user selects an option when prompted for request + to the webcam**; if the user doesn't select anything, the promise won't resolve but our program + won't break. This is the beauty of promises; they allow us to ask for something and will + allow the rest of the program to run the promise waits for a response. Promises represent + _a value which may be available now, in the future, or never_ ([as defined by MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)). If + we receive a `localMediaStream` object as a promise, we'll set the source object of the `video` + element to the _`localMediaStream` object_, and call upon the `play()` method of the `video` element. + If the promise resolves to an error, we'll log out that error message. + +Then, we need to _define a function_ that will be used as the _event handler_ for when the + 'canplay' event of the `video` element is triggered (whenever the user either approves or + denies access to their webcam). The function will adjust the `canvas` element's + `width` and `height` properties to be equivalent to the `video` element's `width` and `height`, + and will return the _interval ID_ of a `setInterval()` method. Within the body of the + `setInterval()` method, we will draw onto the canvas by providing a valid canvas image + source such as an `image` element, a `video` element, another `canvas` element, or an + _image bitmap_. In our case, we want to display the user's webcam feed in the canvas, + so we'll provide the `video` element as as argument to the canvas' draw method. + To manipulate the image using the `input` HTML elements, we'll need to get access + to the _underlying pixel data_ of the image being displayed on the canvas. + We'll declare a `let` variable and define it as the `ImageData` object returned + from calling the `getImageData()` method of the canvas context. The `ImageData` object + returned from this method is exactly what we were looking for: the _underlying pixel data_ + for the current canvas image. We will eventually pass this variable into a function + that will change the values of the pixels depending on the `input` values. + +The `takePhoto()` function that the `button` HTML element is calling on 'click' events + isn't defined; we'll do that next. The `takePhoto()` function should play the audio file + that we referenced earlier with a `const` variable, convert the current canvas image + to a _data URI_, create an `anchor` HTML element (a link) with a _hyperlink reference_ + pointing to the _data URI_ which will download the image to the user's local storage + when clicked, set the inner HTML of that link to be an `image` HTML element referencing + the _data URI_ as the source, and insert this link inside the empty `div` element + with the class `.strip`. + +The last function we'll want to create is one that will bring functionality to the `input` + elements; as the user moves the sliders around, we want to adjust the RGB values of the + canvas image to reflect the values of the sliders to present a sort of 'green screen' + effect. The function should have one declarared parameter, `pixels`. We'll begin by declaring + a `const` as an empty object. We'll create a _NodeList_ of all the HTML `input` elements contained + within the `div` with class `.rgb`, iterate through this _NodeList_, and create a key within + the previously defined object corresponding with the given `input` element's `name` property, + and set it's value as the given `input` element's value. The `pixels` argument we're expecting + will be the _underlying pixel data_ of the current canvas image. This data contains an _array + of unsigned 8bit integer values between 0-255_, corresponding with the RGB attributes of the image. + We'll iterate through these arrays and set the values to 0 where the RGB attribute is within + the range of the input slider values. This one is tricky, so let's get to the steps. + +**Steps:** + +1. Declare a `const` variable `getVideo` and define it as an _arrow function_. This function + will use the `Navigator` and `mediaDevices` web APIs to ask permission to access the user's + webcam and, upon success, will set the source object of the `video` element as the + `localMediaStream`. + + ```JavaScript + const getVideo = () => { + navigator.mediaDevices.getUserMedia({ video: true, audio: false }) + .then(localMediaStream => { + video.srcObject = localMediaStream; + video.play(); + }) + .catch(err => { + console.error(`OH NO!!!`, err); + }) + }; + ``` + +2. Declare a `const` variable `paintToCanvas` and define it as an arrow function. + + ```JavaScript + const paintToCanvas = () => { /* ... */}; + ``` + + - In the body of this function, declare two `const` variables and define them + as the `video` element's width and height, and update the `canvas` width and height + to reflect those values. + + ```JavaScript + const paintToCanavas = () => { + const width = video.videoWidth; + const height = video.videoHeight; + canvas.width = width; + canvas.height = height; + + /* More to do... */ + }; + ``` + + - Still in the body of the function, return the _interval ID_ of a `setInterval()` + function call, and within the body of that function call, draw the current `video` + element on to the `canvas.` + + ```JavaScript + let paintToCanavas = () => { + const width = video.videoWidth; + const height = video.videoHeight; + canvas.width = width; + canvas.height = height; + + return setInterval(() => { + ctx.drawImage(video, 0, 0, width, height); + }, 16); + }; + ``` + +3. Declare a `const` variable `takePhoto` and define it as an arrow function that will + play the `audio` element on the HTML page, create a link which targets a _data URI_ + representation of a still image taken from the canvas, and places that link into the front + of the empty `div` element. + + ```JavaScript + const takePhoto = () => { + // Play the audio element on the HTML page + snap.currentTime = 0; + snap.play(); + + const data = canvas.toDataURL('image/jpeg'); + const link = document.createElement('a'); + link.href = data; + link.setAttribute('download', 'handsome'); + link.innerHTML = `Handsome Man`; + strip.insertBefore(link, strip.firsChild); + }; + ``` + +4. Declare a `const` variable `greenScreen` and define it as an _arrow function_ that will + accept an argument `pixels`. + + ```JavaScript + const greenScreen = (pixels) => { /*...*/ }; + ``` + + - In the function body, declare a `const` variables `levels` and define it as an empty + object. Iterate through a _NodeList_ of all `input` elements within the div with class + `rgb` and set a key in the `levels` object as a given input's `name` property, and + set the value to be the given input's `value`. + + ```JavaScript + /* In function body */ + + const levels = {}; + + document.querySelectorAll('.rgb input').forEach((input) => { + levels[input.name] = input.value; + }); + ``` + + - Update the values of the pixels in the image so that we remove all RGB + values that are within the range defined by the user, and return the given + argument. + + ```JavaScript + /* In function body */ + for (i = 0; i < pixels.data.length; i += 4) { + red = pixels.data[i + 0]; + green = pixels.data[i + 1]; + blue = pixels.data[i + 2]; + alpha = pixels.data[i + 3]; + + if (red >= levels.rmin + && green >= levels.gmin + && blue >= levels.bmin + && red <= levels.rmax + && green <= levels.gmax + && blue <= levels.bmax) + { + pixels.data[i + 3] = 0; + } + } + return pixels; + ``` + +5. Update the `getVideo` function so that the setInterval method within the function body + creates a variable defined as the _underlying pixel data_, passes that variable into the + `greenScreen` function, and places the returned pixel data into the canvas context. + + ```JavaScript + /* In paintToCanvas function body */ + + return setInterval(() => { + ctx.drawImage(video, 0, 0, width, height); + + let pixels = ctx.getImageData(0, 0, width, height); + + pixels = greenScreen(pixels); + + ctx.putImageData(pixels, 0, 0); + }, 16); + ``` + +6. Call upon the `getVideo` function we previously defined. + +7. Attach an _event listener_ to the `video` HTML element that will call the `paintToCanvas` + function on the 'canplay' event, and attach an _event listener_ to the `button` HTML element + that will call the `takePhoto` function on a 'click' event. + + ```JavaScript + video.addEventListener('canplay', paintToCanavas); + document.querySelector('.takePhoto').addEventListener('click', takePhoto); + ``` + +Wrap it all up in an IIFE, take a step back, and enjoy your glorious new photo-and-greenscreen + application! diff --git a/exercises/19 - Webcam Fun/index.html b/exercises/19 - Webcam Fun/index.html index d4ffc4d..21fed87 100755 --- a/exercises/19 - Webcam Fun/index.html +++ b/exercises/19 - Webcam Fun/index.html @@ -9,8 +9,8 @@
- - +
diff --git a/exercises/19 - Webcam Fun/package.json b/exercises/19 - Webcam Fun/package.json deleted file mode 100755 index 616baf5..0000000 --- a/exercises/19 - Webcam Fun/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "gum", - "version": "1.0.0", - "description": "", - "main": "scripts.js", - "scripts": { - "start" : "browser-sync start --server --files '*.css, *.html, *.js'" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "browser-sync": "^2.12.5" - } -} diff --git a/exercises/19 - Webcam Fun/scripts-FINISHED.js b/exercises/19 - Webcam Fun/scripts-FINISHED.js deleted file mode 100755 index 0d62c8d..0000000 --- a/exercises/19 - Webcam Fun/scripts-FINISHED.js +++ /dev/null @@ -1,102 +0,0 @@ -const video = document.querySelector('.player'); -const canvas = document.querySelector('.photo'); -const ctx = canvas.getContext('2d'); -const strip = document.querySelector('.strip'); -const snap = document.querySelector('.snap'); - -function getVideo() { - navigator.mediaDevices.getUserMedia({ video: true, audio: false }) - .then(localMediaStream => { - console.log(localMediaStream); - video.src = window.URL.createObjectURL(localMediaStream); - video.play(); - }) - .catch(err => { - console.error(`OH NO!!!`, err); - }); -} - -function paintToCanavas() { - const width = video.videoWidth; - const height = video.videoHeight; - canvas.width = width; - canvas.height = height; - - return setInterval(() => { - ctx.drawImage(video, 0, 0, width, height); - // take the pixels out - let pixels = ctx.getImageData(0, 0, width, height); - // mess with them - // pixels = redEffect(pixels); - - pixels = rgbSplit(pixels); - // ctx.globalAlpha = 0.8; - - // pixels = greenScreen(pixels); - // put them back - ctx.putImageData(pixels, 0, 0); - }, 16); -} - -function takePhoto() { - // played the sound - snap.currentTime = 0; - snap.play(); - - // take the data out of the canvas - const data = canvas.toDataURL('image/jpeg'); - const link = document.createElement('a'); - link.href = data; - link.setAttribute('download', 'handsome'); - link.innerHTML = `Handsome Man`; - strip.insertBefore(link, strip.firsChild); -} - -function redEffect(pixels) { - for(let i = 0; i < pixels.data.length; i+=4) { - pixels.data[i + 0] = pixels.data[i + 0] + 200; // RED - pixels.data[i + 1] = pixels.data[i + 1] - 50; // GREEN - pixels.data[i + 2] = pixels.data[i + 2] * 0.5; // Blue - } - return pixels; -} - -function rgbSplit(pixels) { - for(let i = 0; i < pixels.data.length; i+=4) { - pixels.data[i - 150] = pixels.data[i + 0]; // RED - pixels.data[i + 500] = pixels.data[i + 1]; // GREEN - pixels.data[i - 550] = pixels.data[i + 2]; // Blue - } - return pixels; -} - -function greenScreen(pixels) { - const levels = {}; - - document.querySelectorAll('.rgb input').forEach((input) => { - levels[input.name] = input.value; - }); - - for (i = 0; i < pixels.data.length; i = i + 4) { - red = pixels.data[i + 0]; - green = pixels.data[i + 1]; - blue = pixels.data[i + 2]; - alpha = pixels.data[i + 3]; - - if (red >= levels.rmin - && green >= levels.gmin - && blue >= levels.bmin - && red <= levels.rmax - && green <= levels.gmax - && blue <= levels.bmax) { - // take it out! - pixels.data[i + 3] = 0; - } - } - - return pixels; -} - -getVideo(); - -video.addEventListener('canplay', paintToCanavas); diff --git a/exercises/19 - Webcam Fun/scripts.js b/exercises/19 - Webcam Fun/scripts.js index 00355f5..2ceeed6 100644 --- a/exercises/19 - Webcam Fun/scripts.js +++ b/exercises/19 - Webcam Fun/scripts.js @@ -1,5 +1,81 @@ -const video = document.querySelector('.player'); -const canvas = document.querySelector('.photo'); -const ctx = canvas.getContext('2d'); -const strip = document.querySelector('.strip'); -const snap = document.querySelector('.snap'); +(() => { + const video = document.querySelector(".player"), + canvas = document.querySelector(".photo"), + ctx = canvas.getContext("2d"), + strip = document.querySelector(".strip"), + snap = document.querySelector(".snap"); + + const getVideo = () => { + navigator.mediaDevices + .getUserMedia({ video: true, audio: false }) + .then(localMediaStream => { + video.srcObject = localMediaStream; + video.play(); + }) + .catch(err => { + console.error(`OH NO!!! ${err}`); + }); + }; + + const paintToCanavas = () => { + const { videoWidth: width, videoHeight: height } = video; + + canvas.width = width; + canvas.height = height; + + return setInterval(() => { + ctx.drawImage(video, 0, 0, width, height); + + let pixels = ctx.getImageData(0, 0, width, height); + + pixels = greenScreen(pixels); + + ctx.putImageData(pixels, 0, 0); + }, 16); + }; + + const takePhoto = () => { + snap.currentTime = 0; + snap.play(); + + const data = canvas.toDataURL("image/jpeg"); + const link = document.createElement("a"); + + link.href = data; + link.setAttribute("download", "handsome"); + link.innerHTML = `Handsome Man`; + strip.insertBefore(link, strip.firsChild); + }; + + const greenScreen = pixels => { + const levels = {}; + + document.querySelectorAll(".rgb input").forEach(input => { + levels[input.name] = input.value; + }); + + for (i = 0; i < pixels.data.length; i += 4) { + red = pixels.data[i + 0]; + green = pixels.data[i + 1]; + blue = pixels.data[i + 2]; + alpha = pixels.data[i + 3]; + + if ( + red >= levels.rmin && + green >= levels.gmin && + blue >= levels.bmin && + red <= levels.rmax && + green <= levels.gmax && + blue <= levels.bmax + ) { + pixels.data[i + 3] = 0; + } + } + return pixels; + }; + + getVideo(); + + video.addEventListener("canplay", paintToCanavas); + document.querySelector(".takePhoto").addEventListener("click", takePhoto); +})(); diff --git a/exercises/20 - Speech Detection/README.md b/exercises/20 - Speech Detection/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/20 - Speech Detection/index-START.html b/exercises/20 - Speech Detection/index-START.html deleted file mode 100644 index d3395cc..0000000 --- a/exercises/20 - Speech Detection/index-START.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - Speech Detection - - - -
-
- - - - - - - - diff --git a/exercises/20 - Speech Detection/index-FINISHED.html b/exercises/20 - Speech Detection/index.html similarity index 57% rename from exercises/20 - Speech Detection/index-FINISHED.html rename to exercises/20 - Speech Detection/index.html index e1932f4..457ab15 100644 --- a/exercises/20 - Speech Detection/index-FINISHED.html +++ b/exercises/20 - Speech Detection/index.html @@ -10,34 +10,33 @@
diff --git a/exercises/21 - Geolocation/README.md b/exercises/21 - Geolocation/README.md new file mode 100644 index 0000000..e69de29 diff --git a/exercises/21 - Geolocation/index-FINISHED.html b/exercises/21 - Geolocation/index-FINISHED.html deleted file mode 100644 index 0f2ddec..0000000 --- a/exercises/21 - Geolocation/index-FINISHED.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - Document - - - - - - -

- 0 - KM/H -

- - - - - diff --git a/exercises/21 - Geolocation/index-START.html b/exercises/21 - Geolocation/index-START.html index d794c14..f51d895 100644 --- a/exercises/21 - Geolocation/index-START.html +++ b/exercises/21 - Geolocation/index-START.html @@ -62,7 +62,9 @@

navigator.geolocation.watchPosition((data) => { console.log(data); - speed.textContent = data.coords.speed; + + const { speed: dSpeed, heading } = data.coords; + speed.textContent = dSpeed; arrow.style.transform = `rotate(${data.coords.heading}deg)`; }, (err) => { console.err(err); diff --git a/readme.md b/readme.md index 2f500c4..ff699a0 100644 --- a/readme.md +++ b/readme.md @@ -1,61 +1,76 @@ # JavaScript30 - 30 Day JavaScript Challenge + Nitish Dayal, Software & Applications Developer -Last Commit Date: Dec 24, 2016 +Last Commit Date: May 12, 2017 -> Course created by [Wes Bos](https://github.com/wesbos) +> Course created by [Wes Bos](https://github.com/wesbos) > Join the challenge (for free!) here - [JavaScript30](https://javascript30.com/account) +This repository contains my written guides for the JavaScript30 course by + [Wes Bos](//github.com/wesbos). I wrote these in the hopes of expanding the ways + in which people can access this course; not everyone has the data allotments + or internet speeds or...whatever the case may be to load multiple high definition + videos. Or, maybe, you prefer to have a text-based guide to follow along with/ + refer back to. Orrr you're in a library and don't have headphones. Who knows! If + you want some documentation to go along with those sweet Wes Bos vids, here you go. + +**DISCLAIMER:** My approach to some of the challenges will vary from the provided answers (found in + the files that end with `-FINISHED` on the main repo). Some of the tweaks are just to + include various 'best practices' and some have huge chunks of differences. I try to provide + thorough explanations when I do stray from the path and explain why I chose to do so, but + I want to make it clear that some of these guides don't go hand-in-hand with the videos. + ## About -Build 30 things in 30 days with vanilla JavaScript; no frameworks, libraries, etc. +Build 30 things in 30 days with vanilla JavaScript; no frameworks, libraries, etc. Pacing is totally up to the individual; if you feel like knocking out 30 challenges in 30 minutes, hey, more power to you, but that would miss the point of this course (IMO). The idea behind these exercises is to utilize small amounts of what would regularly be 'downtime' as moments in which we can build on our knowledge through some simple - exercises. My goal is to _participate_ in 3 challenges per day (watch the videos, take - some notes, etc.) and to _complete_ one challenge per day. + exercises. -The starter files (available [here](https://github.com/wesbos/JavaScript30)) include solutions to - most challenges, so this isn't really meant to be taken as some kind of competition or something. - JavaScript30 appears to be focused more on helping developers enhance their current skillset and - reducing developer reliance on external JS libraries; **if it can be done with a JS library, - it can (probably) be done with vanilla JS.** +I think it's fair to say that, coming into this course, you should have a decent grasp + of JavaScript fundamentals. Comfort when working with functions, callbacks, arrays, + and objects will help a great deal in working through the challenges. If you don't, + **don't worry and do it anyways** <3. It might take you more than downtime to complete + a challenge, but given that these exercises require you to work with those very topics + time and time again, JavaScript30 is still an excellent learning resource. -**UPDATE:** If you're here for written guides, please be patient with me! I've made it a priority -to get as many of these done as possible, as quickly as possible. Thank youuu. ❤️ - -Completed written guides can be found in the corresponding challenge directory (click the links below, folks). +The starter files (available [here](https://github.com/wesbos/JavaScript30)) include solutions to + most challenges, so this isn't really meant to be taken as some kind of competition. + JavaScript30 is focused more on helping developers enhance their current skillset and + reducing developer reliance on external JS libraries; **if it can be done with a JS library, + it can (probably) be done with vanilla JS.** ## Table Of Contents -1. [x] ~~[JavaScript Drum Kit](./exercises/01\ -\ JavaScript\ Drum\ Kit/)~~ -2. [x] ~~[JS + CSS Clock](./exercises/02\ -\ JS\ +\ CSS\ Clock/)~~ -3. [x] ~~[CSS Variables](./exercises/03\ -\ CSS\ Variables/)~~ -4. [x] ~~[Array Cardio, Day 1](./exercises/04\ -\ Array\ Cardio\ Day\ 1/)~~ -5. [x] ~~[Flex Panel Gallery](./exercises/05\ -\ Flex\ Panel\ Gallery/)~~ -6. [x] ~~[Type Ahead](./exercises/06\ -\ Type\ Ahead/)~~ -7. [x] ~~[Array Cardio, Day 2](./exercises/07\ -\ Array\ Cardio\ Day\ 2/)~~ -8. [x] ~~[Fun with HTML5 Canvas](./exercises/08\ -\ Fun\ with\ HTML5\ Canvas/)~~ -9. [x] ~~[Dev Tools Domination](./exercises/09\ -\ Dev\ Tools\ Domination/)~~ -10. [x] ~~[Hold Shift and Check Checkboxes](./exercises/10\ -\ Hold\ Shift\ and\ Check\ Checkboxes/)~~ -11. [x] ~~[Custom Video Player](./exercises/11\ -\ Custom\ Video\ Player/)~~ -12. [x] ~~[Key Sequence Detection](./exercises/12\ -\ Key\ Sequence\ Detection/)~~ -13. [x] ~~[Slide in on Scroll](./exercises/13\ -\ Slide\ in\ on\ Scroll/)~~ -14. [x] ~~[JavaScript References vs. Copying](./exercises/14\ -\ JavaScript\ References\ VS\ Copying)~~ -15. [x] ~~[LocalStorage](./exercises/15\ -\ LocalStorage/)~~ -16. [x] ~~[Mouse Move Shadow](./exercises/16\ -\ Mouse\ Move\ Shadow/)~~ -17. [x] ~~[Sort Without Articles](./exercises/17\ -\ Sort\ Without\ Articles/)~~ -18. [x] ~~[Adding Up Times with Reduce](./exercises/18\ -\ Adding\ Up\ Times\ with\ Reduce/)~~ -19. [ ] Webcam Fun -20. [ ] Speech Detection -21. [ ] Geolocation -22. [ ] Follow Along Link Highlighter -23. [ ] Speech Synthesis -24. [ ] Sticky Nav -25. [ ] Event Capture, Propagation, Bubbling, and Once -26. [ ] Stripe Follow Along Nav -27. [ ] Click and Drag -28. [ ] Video Speed Controller -29. [ ] Countdown Timer -30. [ ] Whack A Mole - +1. [JavaScript Drum Kit](/exercises/01%20-%20JavaScript%20Drum%20Kit) +2. [JS + CSS Clock](/exercises/02%20-%20JS%20%2B%20CSS%20Clock) +3. [CSS Variables](/exercises/03%20-%20CSS%20Variables) +4. [Array Cardio, Day 1](/exercises/04%20-%20Array%20Cardio%20Day%201/) +5. [Flex Panel Gallery](/exercises/05%20-%20Flex%20Panel%20Gallery/) +6. [Type Ahead](/exercises/06%20-%20Type%20Ahead/) +7. [Array Cardio, Day 2](/exercises/07%20-%20Array%20Cardio%20Day%202/) +8. [Fun with HTML5 Canvas](/exercises/08%20-%20Fun%20with%20HTML5%20Canvas/) +9. [Dev Tools Domination](/exercises/09%20-%20DevTools%20Domination/) +10. [Hold Shift and Check Checkboxes](/exercises/10%20-%20Hold%20Shift%20and%20Check%20Checkboxes/) +11. [Custom Video Player](/exercises/11%20-%20Custom%20Video%20Player/) +12. [Key Sequence Detection](/exercises/12%20-%20Key%20Sequence%20Detection/) +13. [Slide in on Scroll](/exercises/13%20-%20Slide%20in%20on%20Scroll/) +14. [JavaScript References vs. Copying](/exercises/14%20-%20JavaScript%20References%20VS%20Copying) +15. [LocalStorage](/exercises/15%20-%20LocalStorage/) +16. [Mouse Move Shadow](/exercises/16%20-%20Mouse%20Move%20Shadow/) +17. [Sort Without Articles](/exercises/17%20-%20Sort%20Without%20Articles/) +18. [Adding Up Times with Reduce](/exercises/18%20-%20Adding%20Up%20Times%20with%20Reduce/) +19. [Webcam Fun](/exercises/19%20-%20Webcam%20Fun/) +20. [Speech Detection](/exercises/20%20-%20Speech%20Detection/) +21. [Geolocation](/exercises/21%20-%20Geolocation/) +22. [Follow Along Link Highlighter](/exercises/22%20-%20Follow%20Along%20Link%20Highlighter/) +23. [Speech Synthesis](/exercises/23%20-%20Speech%20Synthesis/) +24. [Sticky Nav](/exercises/24%20-%20Sticky%20Nav/) +25. [Event Capture, Propagation, Bubbling, and Once](/exercises/25%20-%20Event%20Capture,%20Propagation,%20Bubbling%20and%20Once/) +26. [Stripe Follow Along Nav](/exercises/26%20-%20Stripe%20Follow%20Along%20Nav/) +27. [Click and Drag](/exercises/27%20-%20Click%20and%20Drag/) +28. [Video Speed Controller](/exercises/28%20-%20Video%20Speed%20Controller/) +29. [Countdown Timer](/exercises/29%20-%20Countdown%20Timer/) +30. [Whack A Mole](/exercises/30%20-%20Whack%20A%20Mole/)