From a8aa9952d9339915f90c762f445bb30b45c84f9b Mon Sep 17 00:00:00 2001 From: "Stein, Jeff" Date: Tue, 13 Dec 2016 11:08:13 -0600 Subject: [PATCH 001/119] my verbose version of the drum kit w Wes' keyup event. --- 01 - JavaScript Drum Kit/index-FINISHED.html | 24 +++--- .../{index.html => index-jds.html} | 75 +++++++++++++++---- 01 - JavaScript Drum Kit/style.css | 18 ++--- 3 files changed, 83 insertions(+), 34 deletions(-) rename 01 - JavaScript Drum Kit/{index.html => index-jds.html} (50%) mode change 100644 => 100755 mode change 100644 => 100755 01 - JavaScript Drum Kit/style.css diff --git a/01 - JavaScript Drum Kit/index-FINISHED.html b/01 - JavaScript Drum Kit/index-FINISHED.html index 1a16d0997c..980e60d5a9 100644 --- a/01 - JavaScript Drum Kit/index-FINISHED.html +++ b/01 - JavaScript Drum Kit/index-FINISHED.html @@ -58,26 +58,28 @@ + diff --git a/01 - JavaScript Drum Kit/index.html b/01 - JavaScript Drum Kit/index-jds.html old mode 100644 new mode 100755 similarity index 50% rename from 01 - JavaScript Drum Kit/index.html rename to 01 - JavaScript Drum Kit/index-jds.html index 246639f990..a103c58594 --- a/01 - JavaScript Drum Kit/index.html +++ b/01 - JavaScript Drum Kit/index-jds.html @@ -7,7 +7,6 @@ -
A @@ -59,23 +58,71 @@ diff --git a/01 - JavaScript Drum Kit/style.css b/01 - JavaScript Drum Kit/style.css old mode 100644 new mode 100755 index 3e0a320b37..924873aa28 --- a/01 - JavaScript Drum Kit/style.css +++ b/01 - JavaScript Drum Kit/style.css @@ -3,10 +3,10 @@ html { background:url(http://i.imgur.com/b9r5sEL.jpg) bottom center; background-size: cover; } -body,html { +body,html,kbd { margin: 0; padding: 0; - font-family: sans-serif; + font-family: "Helvetica",sans-serif; } .keys { @@ -20,19 +20,19 @@ body,html { .key { border:4px solid black; border-radius:5px; - margin:1rem; - font-size: 1.5rem; + margin:0.5rem; + font-size: 1.6rem; padding:1rem .5rem; - transition:all .07s; + transition:all 0.1s; width:100px; text-align: center; color:white; - background:rgba(0,0,0,0.4); + background:rgba(0,0,0,0.8); text-shadow:0 0 5px black; } .playing { - transform:scale(1.1); + transform:scale(1.2); border-color:#ffc600; box-shadow: 0 0 10px #ffc600; } @@ -44,7 +44,7 @@ kbd { .sound { font-size: 1.2rem; - text-transform: uppercase; - letter-spacing: 1px; + /*text-transform: uppercase;*/ + letter-spacing: 0.2rem; color:#ffc600; } From 85c4b05375f7366382f2145c93cf01df40eeb2dd Mon Sep 17 00:00:00 2001 From: "Stein, Jeff" Date: Tue, 13 Dec 2016 12:09:28 -0600 Subject: [PATCH 002/119] remove ext dep. comment code. --- 01 - JavaScript Drum Kit/index-jds.html | 48 +++++++++---------------- 01 - JavaScript Drum Kit/style.css | 6 ++-- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/01 - JavaScript Drum Kit/index-jds.html b/01 - JavaScript Drum Kit/index-jds.html index a103c58594..1fcd137e99 100755 --- a/01 - JavaScript Drum Kit/index-jds.html +++ b/01 - JavaScript Drum Kit/index-jds.html @@ -58,19 +58,16 @@ diff --git a/01 - JavaScript Drum Kit/style.css b/01 - JavaScript Drum Kit/style.css index 924873aa28..5ced982692 100755 --- a/01 - JavaScript Drum Kit/style.css +++ b/01 - JavaScript Drum Kit/style.css @@ -1,12 +1,14 @@ html { font-size: 10px; - background:url(http://i.imgur.com/b9r5sEL.jpg) bottom center; - background-size: cover; + /*background:url(http://i.imgur.com/b9r5sEL.jpg) bottom center;*/ + /*background-size: cover;*/ + background-color: #808080; } body,html,kbd { margin: 0; padding: 0; font-family: "Helvetica",sans-serif; + overflow: hidden; } .keys { From 38e0c4c36a88a0f684ee7e1523012ccf66e743df Mon Sep 17 00:00:00 2001 From: "Stein, Jeff" Date: Tue, 13 Dec 2016 12:13:20 -0600 Subject: [PATCH 003/119] my solution to clock problem... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …change CSS so each hand is distinct (using CSS transform that is persistently applied w each interval (1000ms) so it is not overwritten). remove bg img dep. simplify color scheme. --- 02 - JS + CSS Clock/index-jds.html | 173 +++++++++++++++++++++++++++++ 02 - JS + CSS Clock/index.html | 96 ---------------- 2 files changed, 173 insertions(+), 96 deletions(-) create mode 100755 02 - JS + CSS Clock/index-jds.html delete mode 100644 02 - JS + CSS Clock/index.html diff --git a/02 - JS + CSS Clock/index-jds.html b/02 - JS + CSS Clock/index-jds.html new file mode 100755 index 0000000000..b01bea3ba7 --- /dev/null +++ b/02 - JS + CSS Clock/index-jds.html @@ -0,0 +1,173 @@ + + + + + Document + + + +
+
+
+
+
+
+
+
+
+
+ + + + + + diff --git a/02 - JS + CSS Clock/index.html b/02 - JS + CSS Clock/index.html deleted file mode 100644 index 1c777557da..0000000000 --- a/02 - JS + CSS Clock/index.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - JS + CSS Clock - - - - -
-
-
-
-
-
-
- - - - - - - From 4ae191ed4fd7c857c5d3bf897168f0b5985fe339 Mon Sep 17 00:00:00 2001 From: "Stein, Jeff" Date: Tue, 13 Dec 2016 12:14:23 -0600 Subject: [PATCH 004/119] add basic digital clock. --- 02 - JS + CSS Clock/index-jds-digital.html | 116 +++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100755 02 - JS + CSS Clock/index-jds-digital.html diff --git a/02 - JS + CSS Clock/index-jds-digital.html b/02 - JS + CSS Clock/index-jds-digital.html new file mode 100755 index 0000000000..d8b7513b65 --- /dev/null +++ b/02 - JS + CSS Clock/index-jds-digital.html @@ -0,0 +1,116 @@ + + + + + Document + + + +
+
+
+
+
+ + + + + + From 931875d478833caf74bb49e811947b13d32e5e48 Mon Sep 17 00:00:00 2001 From: "Stein, Jeff" Date: Tue, 13 Dec 2016 12:59:26 -0600 Subject: [PATCH 005/119] enhance digital clock. --- 02 - JS + CSS Clock/index-jds-countdown.html | 137 +++++++++++++++++++ 02 - JS + CSS Clock/index-jds-digital.html | 73 ++++++---- 02 - JS + CSS Clock/index-jds.html | 2 +- 3 files changed, 183 insertions(+), 29 deletions(-) create mode 100755 02 - JS + CSS Clock/index-jds-countdown.html diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02 - JS + CSS Clock/index-jds-countdown.html new file mode 100755 index 0000000000..636f268f0e --- /dev/null +++ b/02 - JS + CSS Clock/index-jds-countdown.html @@ -0,0 +1,137 @@ + + + + + JS + CSS Clock (Digital) + + + +
+ +
+
+
+
+
+ +
+ + + + + + diff --git a/02 - JS + CSS Clock/index-jds-digital.html b/02 - JS + CSS Clock/index-jds-digital.html index d8b7513b65..c15b468d54 100755 --- a/02 - JS + CSS Clock/index-jds-digital.html +++ b/02 - JS + CSS Clock/index-jds-digital.html @@ -2,14 +2,18 @@ - Document + JS + CSS Clock (Digital) -
-
-
-
+
+ +
+
+
+
+
+
+
+ diff --git a/02 - JS + CSS Clock/index-jds-digital.html b/02 - JS + CSS Clock/index-jds-digital.html index c15b468d54..add6c8677a 100755 --- a/02 - JS + CSS Clock/index-jds-digital.html +++ b/02 - JS + CSS Clock/index-jds-digital.html @@ -3,126 +3,85 @@ JS + CSS Clock (Digital) +
-
-
-
-
-
+
    +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
- - + + + + diff --git a/03 - CSS Variables/index.html b/03 - CSS Variables/index.html new file mode 100755 index 0000000000..b2e44969d3 --- /dev/null +++ b/03 - CSS Variables/index.html @@ -0,0 +1,16 @@ + + + + + JS Drum Kit + + + + + + + diff --git a/03 - CSS Variables/photo.jpg b/03 - CSS Variables/photo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0eb31940cbf943499f2c72c4a63efefc1bd0836d GIT binary patch literal 135377 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 z�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 + + + + JS Drum Kit + + + + + + + From d748b1bdae148cf998d50e13b1a8f56f3b8f179d Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 14 Dec 2016 16:29:52 -0600 Subject: [PATCH 008/119] improved the countdown.... stack display vertically. add 2 functions to calculate time diff. only one works in reverse. --- 02 - JS + CSS Clock/digital.css | 32 +-- 02 - JS + CSS Clock/index-jds-countdown.html | 206 +++++++++++++++---- 02 - JS + CSS Clock/utils.js | 15 +- 03 - CSS Variables/index-jds.html | 1 + 4 files changed, 195 insertions(+), 59 deletions(-) diff --git a/02 - JS + CSS Clock/digital.css b/02 - JS + CSS Clock/digital.css index 64c8a1e463..ef77b66ad8 100644 --- a/02 - JS + CSS Clock/digital.css +++ b/02 - JS + CSS Clock/digital.css @@ -13,6 +13,9 @@ min-height:100vh; } + ul, ol, dl {list-style-type: none;} + li, dt, dd {text-align: left;} + .wrapper { min-height:100vh; margin:0 auto; @@ -27,6 +30,7 @@ .clock { padding:1rem; + white-space: normal; background:#000; border:3rem solid #333; box-shadow: @@ -37,35 +41,39 @@ } .time, .count { - position:relative; + /*position:relative;*/ /*float:left;*/ display: inline; font-size:5rem; + /*width:2em;*/ + /*min-width:2em;*/ color:rgb(204,51,51); } + .count {display: block;} .time-day {font-size: 2.5rem;} .time-yrs {} .time-mon {} .time-dat {} - .time-hrs {} - .time-min {} - .time-sec {} + .time-hrs, + .time-min, + .time-sec {font-size: 7.5rem;} .time:before, .time:after, .count:before, .count:after {color:#808080;} - .count:before {font-size:2.5rem; padding: 0 0 0 2rem;} - .count:first-of-type:before {padding: 0;} + + .count:before, .count:after {font-size:2.5rem; padding-right:1em; vertical-align: middle; line-height: 1;} + .count:first-of-type:before, .count:last-of-type:after {padding: 0;} .time-yrs:after, .time-mon:after {content:"-";} .time-day:after, .time-dat:after {content:"\a";white-space:pre;} .time-hrs:before {content:"T";} .time-min:before, .time-sec:before {content:":";} - .count-yrs:before {content:"Y:";} - .count-mon:before {content:"M:";} - .count-dat:before {content:"D:";} - .count-hrs:before {content:"h:";} - .count-min:before {content:"m:";} - .count-sec:before {content:"s:";} + .count-yrs:after {content:"Years";} + .count-mon:after {content:"Months";} + .count-dat:after {content:"Days";} + .count-hrs:after {content:"Hours";} + .count-min:after {content:"Minutes";} + .count-sec:after {content:"Seconds";} diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02 - JS + CSS Clock/index-jds-countdown.html index e2b15f1c05..9ace93dba5 100755 --- a/02 - JS + CSS Clock/index-jds-countdown.html +++ b/02 - JS + CSS Clock/index-jds-countdown.html @@ -2,7 +2,7 @@ - JS + CSS Clock (Digital) + JS + CSS Clock (Countdown) @@ -10,12 +10,12 @@
-
From d54fb46ecf2df6ea60d362dc3d5c10f0c9dcca24 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 20 Dec 2016 17:42:49 -0600 Subject: [PATCH 012/119] simplify UI. move script to own file. --- 02 - JS + CSS Clock/README.MD | 18 ++ 02 - JS + CSS Clock/countdown.js | 253 +++++++++++++++++ 02 - JS + CSS Clock/digital.css | 134 +++++---- 02 - JS + CSS Clock/index-jds-countdown.html | 276 ++----------------- 4 files changed, 358 insertions(+), 323 deletions(-) create mode 100644 02 - JS + CSS Clock/README.MD create mode 100644 02 - JS + CSS Clock/countdown.js diff --git a/02 - JS + CSS Clock/README.MD b/02 - JS + CSS Clock/README.MD new file mode 100644 index 0000000000..f915d91489 --- /dev/null +++ b/02 - JS + CSS Clock/README.MD @@ -0,0 +1,18 @@ +README.MD + +# Project + +* by Jeff Stein + +## About + +App that estimates the amount of time between two dates. + +## FAQ + +* Why is it an "estimate"? + * It is notoriously difficult to account for all the calendar variations that happen between two dates. Thanks to irregular month lengths and leap years, the farther apart two dates are, the more difficult it is to count the exact number of days between them. And then there are leap seconds! + +## Resources + +* [http://howlonghasobamabeenpresident.com/](http://howlonghasobamabeenpresident.com/) \ No newline at end of file diff --git a/02 - JS + CSS Clock/countdown.js b/02 - JS + CSS Clock/countdown.js new file mode 100644 index 0000000000..300110dde8 --- /dev/null +++ b/02 - JS + CSS Clock/countdown.js @@ -0,0 +1,253 @@ +/* countdown.js */ + + /* the below is the only format (date.toISOString()) that input[type="datetime-local"] accepts */ + const defTime = "2018-01-01T06:00:00"; + const defTimeArr = defTime.split("T"); + // console.log('defTimeArr: ', defTimeArr); + + let flagState = ''; + + /* cache dome objs */ + const grids = document.querySelectorAll(".grid"); + const msgFuture = document.querySelectorAll(".future"); + const msgPast = document.querySelectorAll(".past"); + + const counts = document.querySelectorAll(".count-yrs, .count-mon, .count-day"); + + const yrs = document.querySelector(".count-yrs"); + const mon = document.querySelector(".count-mon"); + const day = document.querySelector(".count-day"); + const hrs = document.querySelector(".count-hrs"); + const min = document.querySelector(".count-min"); + const sec = document.querySelector(".count-sec"); + + const linkEdit = document.querySelector("#link-edit"); + + const elNow = document.querySelector("#now"); + const elNowOffset = document.querySelector("#nowOffset"); + + const elThen = document.querySelector("#then"); + const elThenOffset = document.querySelector("#thenOffset"); + + const elThenDate2 = document.querySelector("#then-date2"); + const elThenTime2 = document.querySelector("#then-time2"); + + elThen.value = defTime; + // elThenDate2.value = defTimeArr[0]; + // elThenTime2.value = defTimeArr[1]; + + // let now = new Date(); + // console.log('now: ', now); + + let then = new Date(defTime); + console.log('then: ', then); + + timezoneOffset(then, elThenOffset); + + // console.log('then.toDateString(): ', then.toDateString()); + console.log('Date.UTC(then): ', Date.UTC(then)); + console.log('then.toUTCString(): ', then.toUTCString()); + console.log('then.toGMTString(): ', then.toGMTString()); + // console.log('then.toISOString(): ', then.toISOString()); + // console.log('then.toJSON(): ', then.toJSON()); + // console.log('then.toLocaleDateString(): ', then.toLocaleDateString()); + // console.log('then.toLocaleString(): ', then.toLocaleString()); + // console.log('then.toLocaleTimeString(): ', then.toLocaleTimeString()); + // console.log('then.toString(): ', then.toString()); + // console.log('then.toTimeString(): ', then.toTimeString()); + // elThen.innerHTML = then.toISOString(); + + elThen.addEventListener("change", function(){ + console.log('elThen: ', elThen.value); + // calculate(elThen.value); + then = new Date(elThen.value); + // elThen.innerHTML = then; + timeUpdate(); + }); + + linkEdit.addEventListener("click", function(){ + console.log('linkEdit: ', linkEdit); + elThen.focus(); + }); + + /** + * get current time ("now") and find difference between "now" and "then" + * @return {[type]} [description] + */ + function timeUpdate() { + + const now = new Date(); + // console.log('now: ', now); + elNow.value = now.toISOString().slice(0, -5); + // console.log('now: ', now.toISOString().slice(0, -5)); + timezoneOffset(now, elNowOffset); + const nowTime = now.getTime(); + // console.log('nowTime: ', nowTime); + + // console.log('then: ', then); + // console.log('then.toString(): ', then.toString()); + const thenTime = then.getTime(); + // console.log('thenTime: ', thenTime); + + const milliseconds = thenTime - nowTime; + // console.log('milliseconds: ', milliseconds); + + timePrint(thenTime,nowTime); + + msgFuture.forEach(msg => msg.classList.remove('hi')); + msgPast.forEach(msg => msg.classList.remove('hi')); + + if (milliseconds > 0) { + // the "then" date is in the future + console.log('future'); + flagState = 'future'; + msgPast.forEach(msg => msg.classList.add('hi')); + msgFuture.forEach(msg => msg.classList.remove('hi')); + } else if (milliseconds < 0) { + // the "then" date is in the past + console.log('past'); + flagState = 'past'; + msgPast.forEach(msg => msg.classList.remove('hi')); + msgFuture.forEach(msg => msg.classList.add('hi')); + } else { + // the "then" date is in the present + console.log('present'); + flagState = 'present'; + } + + // timeDiff(milliseconds); + + }; + + function timePrint (then,now) { + console.group('START timePrint'); + + const seconds = Math.abs(then-now)/1000; + console.log('seconds: ', seconds); + + let temp = Math.floor(seconds); + console.log('temp: ', temp); + + // units.forEach(unit => console.log('JDS -- unit: ', unit)); + + for (var i = 0; i < Object.keys(units).length; i++) { + // for (var i = Object.keys(units).length - 1; i >= 0; i--) { + console.group('JDS -- Object.keys(units)[i]: ', Object.keys(units)[i]); + + var r = i-1; + let result = 0; + const iKey = Object.keys(units)[i]; + console.log('iKey el: ',document.querySelector('.count-'+iKey)); + const rKey = Object.keys(units)[r]; + + if (iKey==='yrs') { + console.log('JDS -- YEARS // temp: ', temp); + // console.log('JDS -- years // units[iKey]: ', units[iKey]); + result = Math.floor(temp / units[iKey]); + } else if (iKey==='sec') { + console.log('JDS -- SECONDS // temp: ', temp); + // console.log('JDS -- seconds // units[iKey]: ', units[iKey]); + result = Math.floor(temp % units[rKey]); + } else { + console.log('JDS -- '+iKey+' // temp: ', temp); + // console.log('JDS -- '+iKey+' // units[iKey]: ', units[iKey]); + result = Math.floor((temp %= units[rKey]) / (units[iKey])); + } + let method = dateFunctions[iKey]; + console.log('test', new Date()[method]()); + + if (method==='getMonth') { + document.querySelector('.now-'+iKey).innerHTML = pad(new Date(now)[method]()+1, 2); + document.querySelector('.then-'+iKey).innerHTML = pad(new Date(then)[method]()+1, 2); + } else { + document.querySelector('.now-'+iKey).innerHTML = pad(new Date(now)[method](), 2); + document.querySelector('.then-'+iKey).innerHTML = pad(new Date(then)[method](), 2); + } + + // document.querySelector('.count-'+iKey).innerHTML = pad(result, 2); + document.querySelector('.delta-'+iKey).innerHTML = pad(result, 2); + document.querySelector('.count-'+iKey).innerHTML = pad(result, 2); + console.log('JDS -- result: ', result+' '+iKey); + console.groupEnd(); + } + + hideZeroes(counts); + + console.groupEnd(); + + }; + + function timeDiff (time) { + + var seconds = Math.abs(time)/1000; + console.log('seconds: ', seconds); + + // function numberEnding (number) { + // return (number > 1) ? 's' : ''; + // } + + var temp = Math.floor(seconds); + // console.log('temp: ', temp); + + var numYears = Math.floor(temp / units.years); + // console.log('numYears: ', numYears); + yrs.innerHTML = pad(numYears, 2); + + //TODO: Months! Maybe weeks? + var numMonths = Math.floor((temp %= units.years) / units.months); + // console.log('numMonths: ', numMonths); + mon.innerHTML = pad(numMonths, 2); + + var numDays = Math.floor((temp %= units.months) / units.days); + // console.log('numDays: ', numDays); + day.innerHTML = pad(numDays, 2); + + var numHours = Math.floor((temp %= units.days) / units.hours); + // console.log('numHours: ', numHours); + hrs.innerHTML = pad(numHours, 2); + + var numMinutes = Math.floor((temp %= units.hours) / units.minutes); + // console.log('numMinutes: ', numMinutes); + min.innerHTML = pad(numMinutes, 2); + + var numSeconds = Math.floor(temp % units.minutes); + // console.log('numSeconds: ', numSeconds); + sec.innerHTML = pad(numSeconds, 2); + + hideZeroes(counts); + + // console.log( numYears + " years " + numMonths + " Months " + numDays + " days " + numHours + " hours " + numMinutes + " minutes " + numSeconds + " seconds" ); + + }; + + function hideZeroes (things) { + things.forEach(thing => {if (thing.innerHTML === '00') {thing.style.display = 'none'} else {thing.style.display = 'table-cell'}}); + } + + function timezoneOffset (time, el) { + console.log('el: ', el.tagName); + const offset = time.getTimezoneOffset()/60; + // const el = time; + let string = ''; + if (offset > 0) { + string = 'UTC+'+offset; + } else if (offset < 0) { + string = 'UTC-'+offset; + } else { + string = 'UTC'; + } + if (el.tagName) { + if (el.tagName === 'INPUT') { + el.value = string; + } else { + el.innerHTML = string; + } + } else { + console.log('el.tagName error!'); + } + } + + timeUpdate(); + setInterval(timeUpdate, 1000); + + grids.forEach(grid => grid.style.display = 'none'); diff --git a/02 - JS + CSS Clock/digital.css b/02 - JS + CSS Clock/digital.css index 102af30e77..ed35ed772e 100644 --- a/02 - JS + CSS Clock/digital.css +++ b/02 - JS + CSS Clock/digital.css @@ -1,13 +1,14 @@ *, *:before, *:after {padding:0; margin:0;} html { - background-color:#666; + background-color:#808080; } html, body { font-family:"Andale Mono", "Lucida Console", Monaco, monospace; /*font-size:1em;*/ font-size:100%; + line-height: 1; min-height:100vh; text-align:center; } @@ -15,6 +16,8 @@ html, body { ul, ol, dl {list-style-type:none;} li, dt, dd {text-align:left;} +a, a:link, a:hover, a:visited, a:active {text-decoration: none; border-bottom: 2px solid #000;} + .wrapper { min-height:100vh; margin:0 auto; @@ -25,46 +28,66 @@ li, dt, dd {text-align:left;} justify-content:center; } +.bttf .time-circuits { + background-image: url('brushed-steel.jpg'); + background-position: center; + background-size:cover; +} + +.module { + box-shadow: + 0 0.5rem 1rem 0 rgba(0, 0, 0, 0.25), + 0 0 0.75rem 0 rgba(0, 0, 0, 0.125); + margin: 1rem 0; +} + .clock { - padding:0.5rem; - /*margin:0.5rem;*/ + padding:0.5rem 0; + margin:0.5rem 0; font-size:2rem; white-space:normal; - background:#111; - color:rgb(204,51,51); + background-color:#111; + color:rgb(204,204,204); border:0.5rem inset #333; - /*box-shadow: - 0 0 2rem 0.25rem rgba(0,0,0,0.25), - inset 0 0.5rem 0 0 rgba(255,255,255,0.75), - inset 0 -1rem 2.5rem 0 rgba(0,0,0,0.75), - 0 1rem 1rem rgba(0,0,0,0.125);*/ } +ul.clock {padding:1rem;} + +.clock-now .display, .module strong {color:rgb(204,51,51);} +.clock-then .display, .module em {color:rgb(51,153,51);} +.clock-delta .display, .module .hi, .count:before, .count:after {color:rgb(51,153,204);} + form, fieldset, legend, label, input, button, textarea, select, option { font-family:"Andale Mono", "Lucida Console", Monaco, monospace; text-align:center; /*display:inline-block;*/ /*width: auto;*/ - padding:0.25rem; - margin:0.25rem; + padding:0.25rem 0; + margin:0.25rem 0; border:none; color:#333; } fieldset { - margin:1rem 0; + margin:0.5rem 0; position: relative; - /*display:flex;*/ - /*flex-direction:row;*/ - /*align-content:center;*/ - /*align-items:center;*/ - /*justify-content:center;*/ } -legend {position: relative; - /*top: -2rem; left:0; bottom:auto; right:0;*/ +legend, label { + font-size: 1.5rem; + font-weight:900; + width: 100%; + margin: 0 auto -0.75rem; + padding: 0.5em 0; +} +.module, legend, label { + color:rgb(102,102,102); + background-color:rgb(204,204,204); +} +legend { + padding-top: 0.75em; + margin-bottom: -1rem; } input, button, textarea, select { - /*margin:0.75rem auto;*/ min-height: 3rem; } @@ -72,10 +95,9 @@ fieldset, label, input, button, textarea, select {/*display:inline-block;*/} label { text-align: left; - font-weight:900; - font-size: 1.5rem; - /*padding:0 0.25rem;*/ - /*margin:0 0.25rem;*/ + text-indent: 0.5rem; + /* padding:0.25rem 0.25rem 0; */ + /* margin:0.25rem 0.25rem 0; */ } fieldset label {display: block;} label input:first-of-type, @@ -84,52 +106,29 @@ label textarea:first-of-type, label select:first-of-type {} .timezone { - width: 8rem; - /*background:none; border:none;*/ - /*padding:0.25rem 0;*/ - /*margin:0.25rem 0;*/ -} -.module { - background-color:rgba(255,255,255,0.5); - /*background-image: url('brushed-steel.jpg');*/ - /*background-position: center;*/ - /*background-size:cover;*/ - box-shadow: 0 1rem 4rem 0 rgba(0, 0, 0, 0.5); + width: 8rem; + background:none; border:none; + padding:0; + margin:0; } -legend { - background-color:#fff; - color:#999; - top:0; - margin: 0 auto; -} +span.timezone {float:right; padding: 0.75rem 1rem 0; width:auto;} .time, .count { - /*position:relative;*/ display:inline; - /*width:2em;*/ - /*min-width:2em;*/ } .count, li.count, td.count { display:table-cell; } -.time-day {/*font-size:2.5rem;*/} -.time-yrs {} -.time-mon {} -.time-dat {} -.time-hrs, -.time-min, -.time-sec {/*font-size:7.5rem;*/} - .time:before, .time:after, -.count:before, .count:after {color:#808080;} +.count:before, .count:after {/* color:#808080; */} .count:before, .count:after, th { font-size:0.6em; padding-right:1em; - vertical-align:middle; - line-height:1; + vertical-align:baseline; + /* line-height:1; */ } .count:first-of-type:before, .count:last-of-type:after {padding:0;} @@ -145,16 +144,15 @@ legend { .count-min:after/*, .delta-min:after*/ {content:"Minutes";} .count-sec:after/*, .delta-sec:after*/ {content:"Seconds";} - -.hi { - /*color:rgb(204,51,51);*/ - color:rgb(51,51,51); - background-color:rgba(255,204,0,0.5); - padding:0.5em; - font-weight:900; - font-size:1.125em; - /*text-decoration:underline;*/ +.future, .past { + border:none; + display: none; } - -*[disabled], *[readonly] {color:#666;} -*[class*='count-'] {color:rgb(51,204,51);} +strong, em, .hi { + text-decoration: none; + font-variant: normal; + font-style: normal; + font-weight: 900; + display: inline; +} +.hi {/* display: inline; */} diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02 - JS + CSS Clock/index-jds-countdown.html index 49dbb40da3..17369090b5 100755 --- a/02 - JS + CSS Clock/index-jds-countdown.html +++ b/02 - JS + CSS Clock/index-jds-countdown.html @@ -55,30 +55,34 @@ -
-
- + +
+ + - + +
-
- - +
+ + + edit + +
-
- [time elapsed|countdown] [since|until] - -
    +
    + time elapsedleft between now and then + + +
    • @@ -87,250 +91,12 @@
    - - +
- - From b47a28fa1aa525c5053935c95839ac9e6f746ac3 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 20 Dec 2016 17:55:13 -0600 Subject: [PATCH 013/119] enhance UI. --- 02 - JS + CSS Clock/digital.css | 20 +++++++++++--------- 02 - JS + CSS Clock/index-jds-countdown.html | 1 + 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/02 - JS + CSS Clock/digital.css b/02 - JS + CSS Clock/digital.css index ed35ed772e..d875b07945 100644 --- a/02 - JS + CSS Clock/digital.css +++ b/02 - JS + CSS Clock/digital.css @@ -13,6 +13,8 @@ html, body { text-align:center; } +p {margin: 1em 0;} + ul, ol, dl {list-style-type:none;} li, dt, dd {text-align:left;} @@ -38,12 +40,13 @@ a, a:link, a:hover, a:visited, a:active {text-decoration: none; border-bottom: 2 box-shadow: 0 0.5rem 1rem 0 rgba(0, 0, 0, 0.25), 0 0 0.75rem 0 rgba(0, 0, 0, 0.125); - margin: 1rem 0; + margin: 1rem 0 0; + padding:0.25rem; } .clock { - padding:0.5rem 0; - margin:0.5rem 0; + padding:0.5rem 0 0; + margin:0.5rem 0 0; font-size:2rem; white-space:normal; background-color:#111; @@ -62,21 +65,20 @@ form, fieldset, legend, label, input, button, textarea, select, option { text-align:center; /*display:inline-block;*/ /*width: auto;*/ - padding:0.25rem 0; - margin:0.25rem 0; + padding:0; + margin:0; border:none; color:#333; } fieldset { - margin:0.5rem 0; position: relative; } legend, label { font-size: 1.5rem; font-weight:900; width: 100%; - margin: 0 auto -0.75rem; + margin: 0.25em auto -0.5rem; padding: 0.5em 0; } .module, legend, label { @@ -84,8 +86,8 @@ legend, label { background-color:rgb(204,204,204); } legend { - padding-top: 0.75em; - margin-bottom: -1rem; + padding: 0.75em 0.25rem 0.25em; + /* margin-bottom: -1rem; */ } input, button, textarea, select { min-height: 3rem; diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02 - JS + CSS Clock/index-jds-countdown.html index 17369090b5..97ea3079c2 100755 --- a/02 - JS + CSS Clock/index-jds-countdown.html +++ b/02 - JS + CSS Clock/index-jds-countdown.html @@ -93,6 +93,7 @@ +

all time measurements are approximate

From 510fa022ec369b376dfc9d585d0d6ef14058161b Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 21 Dec 2016 12:55:02 -0600 Subject: [PATCH 014/119] unify digital & countdown UI. --- 02 - JS + CSS Clock/bttf.css | 6 + 02 - JS + CSS Clock/countdown.css | 34 +++ 02 - JS + CSS Clock/countdown.js | 29 +-- 02 - JS + CSS Clock/digital.css | 213 +++++++++---------- 02 - JS + CSS Clock/digital.js | 69 ++++++ 02 - JS + CSS Clock/index-jds-countdown.html | 23 +- 02 - JS + CSS Clock/index-jds-digital.html | 94 ++------ 02 - JS + CSS Clock/utils.js | 25 ++- 8 files changed, 264 insertions(+), 229 deletions(-) create mode 100644 02 - JS + CSS Clock/bttf.css create mode 100644 02 - JS + CSS Clock/countdown.css create mode 100644 02 - JS + CSS Clock/digital.js diff --git a/02 - JS + CSS Clock/bttf.css b/02 - JS + CSS Clock/bttf.css new file mode 100644 index 0000000000..9ee3779ed1 --- /dev/null +++ b/02 - JS + CSS Clock/bttf.css @@ -0,0 +1,6 @@ +.bttf .time-circuits { + background-image:url('brushed-steel.jpg'); + background-position:center; + background-size:cover; +} + diff --git a/02 - JS + CSS Clock/countdown.css b/02 - JS + CSS Clock/countdown.css new file mode 100644 index 0000000000..bc857c73d3 --- /dev/null +++ b/02 - JS + CSS Clock/countdown.css @@ -0,0 +1,34 @@ +/* countdown.css */ + +.count { + display:inline-block; +} +.count, li.count, td.count { + /* display:table-cell; */ + /* width: auto; */ +} + +.count:before, .count:after, th { + font-size:0.6em; + padding-right:1em; + vertical-align:baseline; +} +.count:first-of-type:before, .count:last-of-type:after {padding:0;} + +.count-yrs:after {content:"Years";} +.count-mon:after {content:"Months";} +.count-day:after {content:"Days";} +.count-hrs:after {content:"Hours";} +.count-min:after {content:"Minutes";} +.count-sec:after {content:"Seconds";} + +.future, .past { + border:none; + display:none; +} + +#disclaimer { + position:absolute; + top:auto; + bottom:0; +} diff --git a/02 - JS + CSS Clock/countdown.js b/02 - JS + CSS Clock/countdown.js index 300110dde8..b8f326bfbd 100644 --- a/02 - JS + CSS Clock/countdown.js +++ b/02 - JS + CSS Clock/countdown.js @@ -57,6 +57,7 @@ // console.log('then.toTimeString(): ', then.toTimeString()); // elThen.innerHTML = then.toISOString(); +if (elThen) { elThen.addEventListener("change", function(){ console.log('elThen: ', elThen.value); // calculate(elThen.value); @@ -64,11 +65,14 @@ // elThen.innerHTML = then; timeUpdate(); }); +} +if (linkEdit) { linkEdit.addEventListener("click", function(){ console.log('linkEdit: ', linkEdit); elThen.focus(); }); +} /** * get current time ("now") and find difference between "now" and "then" @@ -221,30 +225,7 @@ }; function hideZeroes (things) { - things.forEach(thing => {if (thing.innerHTML === '00') {thing.style.display = 'none'} else {thing.style.display = 'table-cell'}}); - } - - function timezoneOffset (time, el) { - console.log('el: ', el.tagName); - const offset = time.getTimezoneOffset()/60; - // const el = time; - let string = ''; - if (offset > 0) { - string = 'UTC+'+offset; - } else if (offset < 0) { - string = 'UTC-'+offset; - } else { - string = 'UTC'; - } - if (el.tagName) { - if (el.tagName === 'INPUT') { - el.value = string; - } else { - el.innerHTML = string; - } - } else { - console.log('el.tagName error!'); - } + things.forEach(thing => {if (thing.innerHTML === '00') {thing.style.display = 'none'} else {thing.style.display = 'inline'}}); } timeUpdate(); diff --git a/02 - JS + CSS Clock/digital.css b/02 - JS + CSS Clock/digital.css index d875b07945..a289424e34 100644 --- a/02 - JS + CSS Clock/digital.css +++ b/02 - JS + CSS Clock/digital.css @@ -1,4 +1,6 @@ -*, *:before, *:after {padding:0; margin:0;} +/* analog.css */ + +*, *:before, *:after {padding:0;margin:0;text-align:left;} html { background-color:#808080; @@ -6,65 +8,21 @@ html { html, body { font-family:"Andale Mono", "Lucida Console", Monaco, monospace; - /*font-size:1em;*/ font-size:100%; - line-height: 1; + line-height:1; min-height:100vh; - text-align:center; } -p {margin: 1em 0;} +p {margin:1em 0;} ul, ol, dl {list-style-type:none;} -li, dt, dd {text-align:left;} +li, dt, dd {} -a, a:link, a:hover, a:visited, a:active {text-decoration: none; border-bottom: 2px solid #000;} - -.wrapper { - min-height:100vh; - margin:0 auto; - display:flex; - flex-direction:column; - align-content:center; - align-items:center; - justify-content:center; -} - -.bttf .time-circuits { - background-image: url('brushed-steel.jpg'); - background-position: center; - background-size:cover; -} - -.module { - box-shadow: - 0 0.5rem 1rem 0 rgba(0, 0, 0, 0.25), - 0 0 0.75rem 0 rgba(0, 0, 0, 0.125); - margin: 1rem 0 0; - padding:0.25rem; -} - -.clock { - padding:0.5rem 0 0; - margin:0.5rem 0 0; - font-size:2rem; - white-space:normal; - background-color:#111; - color:rgb(204,204,204); - border:0.5rem inset #333; -} - -ul.clock {padding:1rem;} - -.clock-now .display, .module strong {color:rgb(204,51,51);} -.clock-then .display, .module em {color:rgb(51,153,51);} -.clock-delta .display, .module .hi, .count:before, .count:after {color:rgb(51,153,204);} +a, a:link, a:hover, a:visited, a:active {text-decoration:none; border-bottom:2px solid #000;} form, fieldset, legend, label, input, button, textarea, select, option { font-family:"Andale Mono", "Lucida Console", Monaco, monospace; - text-align:center; - /*display:inline-block;*/ - /*width: auto;*/ + /* text-align:center; */ padding:0; margin:0; border:none; @@ -72,89 +30,124 @@ form, fieldset, legend, label, input, button, textarea, select, option { } fieldset { - position: relative; + position:relative; } legend, label { - font-size: 1.5rem; + /* background-color:rgb(204,204,204); */ + /* display:inline; */ + text-align:left; + font-size:1.25rem; font-weight:900; - width: 100%; - margin: 0.25em auto -0.5rem; - padding: 0.5em 0; -} -.module, legend, label { - color:rgb(102,102,102); - background-color:rgb(204,204,204); + /* width:100%; */ + margin:0.25em auto -0.5rem; + padding:0.5em; + /* position:absolute; */ + /* top:0; */ + /* left:0; */ } legend { - padding: 0.75em 0.25rem 0.25em; - /* margin-bottom: -1rem; */ + background-color:rgb(0,204,204); + /* padding-left:0.25rem; */ + /* padding-right:0.25rem; */ } input, button, textarea, select { - min-height: 3rem; + min-height:3rem; + min-width:100%; } -fieldset, label, input, button, textarea, select {/*display:inline-block;*/} +/* classes */ -label { - text-align: left; - text-indent: 0.5rem; - /* padding:0.25rem 0.25rem 0; */ - /* margin:0.25rem 0.25rem 0; */ +.wrapper { + min-height:100vh; + margin:0 5%; + display:flex; + flex-direction:column; + align-items:stretch; + justify-content:center; + align-content:center; } -fieldset label {display: block;} -label input:first-of-type, -label button:first-of-type, -label textarea:first-of-type, -label select:first-of-type {} - -.timezone { - width: 8rem; - background:none; border:none; - padding:0; - margin:0; +.clock-now {order: 1;} +.clock-then {order: 2;} +.clock-delta {order: 3;} + +.module { + color:rgb(153,153,153); + background-color:rgb(204,204,204); + box-shadow: + 0 1rem 3rem 0 rgba(0, 0, 0, 0.5), + 0 0 0.5rem 0rem rgba(0, 0, 0, 0.5); + margin:2rem 0 0; + padding:0.25rem; + position:relative; + text-align:left; } -span.timezone {float:right; padding: 0.75rem 1rem 0; width:auto;} -.time, .count { - display:inline; -} -.count, li.count, td.count { - display:table-cell; +.clock { + display:block; + margin:0.125rem 0 0; + font-size:2rem; + line-height:1; + white-space:normal; + background-color:#111; + color:#999; + text-align:center; + /* border:0.5rem inset #333; */ + /* text-align:justify-all; */ } +input.clock {padding:0.5em 0;} +ul.clock {padding:0.75em 1rem;} -.time:before, .time:after, -.count:before, .count:after {/* color:#808080; */} - -.count:before, .count:after, th { - font-size:0.6em; - padding-right:1em; - vertical-align:baseline; - /* line-height:1; */ +.time { + display:inline; } -.count:first-of-type:before, .count:last-of-type:after {padding:0;} +.time-day {font-size:1.4em;} +.time-yrs, .time-mon, .time-dat {font-size:1.2em;} +.time-hrs, .time-min, .time-sec {font-size:1.6em;} .time-yrs:after, .time-mon:after {content:"-";} .time-day:after, .time-dat:after {content:"\a";white-space:pre;} -.time-hrs:before {content:"T";} +.time-hrs:before {/* content:"T"; */} .time-min:before, .time-sec:before {content:":";} -.count-yrs:after/*, .delta-yrs:after*/ {content:"Years";} -.count-mon:after/*, .delta-mon:after*/ {content:"Months";} -.count-day:after/*, .delta-day:after*/ {content:"Days";} -.count-hrs:after/*, .delta-hrs:after*/ {content:"Hours";} -.count-min:after/*, .delta-min:after*/ {content:"Minutes";} -.count-sec:after/*, .delta-sec:after*/ {content:"Seconds";} +.now, +.clock-now .clock, +.clock-now .display, +.clock-now .timezone {color:rgb(204,51,51);} + +.then, +.clock-then .clock, +.clock-then .display, +.clock-then .timezone {color:rgb(51,153,51);} + +.delta, +.clock-delta .clock, +.clock-delta .display, +.clock-delta .timezone {color:rgb(51,153,204);} -.future, .past { +.hi { + background-color:#111; + text-decoration:none; + font-variant:normal; + font-style:normal; + font-weight:900; + display:inline !important; + padding:1rem; + margin:0 -0.5rem; +} + +input.timezone { + width:8rem; + background:none; border:none; - display: none; + padding:0; + margin:0; } -strong, em, .hi { - text-decoration: none; - font-variant: normal; - font-style: normal; - font-weight: 900; - display: inline; + +span.timezone { + position:absolute; + right:0; + bottom:0; + padding:2em 2rem; + width:auto; } -.hi {/* display: inline; */} diff --git a/02 - JS + CSS Clock/digital.js b/02 - JS + CSS Clock/digital.js new file mode 100644 index 0000000000..6f7cb0ad80 --- /dev/null +++ b/02 - JS + CSS Clock/digital.js @@ -0,0 +1,69 @@ + +let dayType = "long"; +let monthType = "short"; + +const day = document.querySelector(".time-day"); +day.style.fontWeight = bold; +const yrs = document.querySelector(".time-yrs"); +const mon = document.querySelector(".time-mon"); +const dat = document.querySelector(".time-dat"); +const hrs = document.querySelector(".time-hrs"); +const min = document.querySelector(".time-min"); +const sec = document.querySelector(".time-sec"); + +const elOffset = document.querySelector("#nowOffset"); + + +function updateTime(type) { + + const now = new Date(); + // console.log('now: ', now); + + timezoneOffset(now, elOffset); + + const nowDay = days[dayType][now.getDay()]; + // console.log('nowDay: ', nowDay); + switch(dayType) { + case 'number': + day.innerHTML = pad(nowDay, 2); + break; + default: + day.innerHTML = nowDay; + break; + } + + const nowYrs = now.getFullYear(); + // console.log('nowYrs: ', nowYrs); + yrs.innerHTML = pad(nowYrs, 4); + + const nowMon = months[monthType][now.getMonth()]; + // console.log('nowMon: ', nowMon); + switch(monthType) { + case 'number': + mon.innerHTML = pad(nowMon, 2); + break; + default: + mon.innerHTML = nowMon; + break; + } + + const nowDat = now.getDate(); + // console.log('nowDat: ', nowDat); + dat.innerHTML = pad(nowDat, 2); + + const nowHrs = now.getHours(); + // console.log('nowHrs: ', nowHrs); + hrs.innerHTML = pad(nowHrs, 2); + + const nowMin = now.getMinutes(); + // console.log('nowMin: ', nowMin); + min.innerHTML = pad(nowMin, 2); + + const nowSec = now.getSeconds(); + // console.log('nowSec: ', nowSec); + sec.innerHTML = pad(nowSec, 2); + +}; + +setInterval(updateTime, 1000); + diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02 - JS + CSS Clock/index-jds-countdown.html index 97ea3079c2..c1e2342303 100755 --- a/02 - JS + CSS Clock/index-jds-countdown.html +++ b/02 - JS + CSS Clock/index-jds-countdown.html @@ -4,6 +4,7 @@ JS + CSS Clock (Countdown) + @@ -57,31 +58,17 @@
- - - - + +
- - + -
-
- time elapsedleft between now and then - - +
  • diff --git a/02 - JS + CSS Clock/index-jds-digital.html b/02 - JS + CSS Clock/index-jds-digital.html index add6c8677a..0287c9d980 100755 --- a/02 - JS + CSS Clock/index-jds-digital.html +++ b/02 - JS + CSS Clock/index-jds-digital.html @@ -8,85 +8,27 @@
    - -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    - +
    + + +
      +
    • +
    +
      +
    • +
    • +
    • +
    +
      +
    • +
    • +
    • +
    +
    - - diff --git a/02 - JS + CSS Clock/utils.js b/02 - JS + CSS Clock/utils.js index 28417f2a12..4b3b17e889 100644 --- a/02 - JS + CSS Clock/utils.js +++ b/02 - JS + CSS Clock/utils.js @@ -59,4 +59,27 @@ const dateFunctions = { "hrs":"getHours", "min":"getMinutes", "sec":"getSeconds" -}; \ No newline at end of file +}; + +function timezoneOffset (time, el) { + console.log('el: ', el.tagName); + const offset = time.getTimezoneOffset()/60; + // const el = time; + let string = ''; + if (offset > 0) { + string = 'UTC+'+offset; + } else if (offset < 0) { + string = 'UTC-'+offset; + } else { + string = 'UTC'; + } + if (el.tagName) { + if (el.tagName === 'INPUT') { + el.value = string; + } else { + el.innerHTML = string; + } + } else { + console.log('el.tagName error!'); + } +} From 0547d896abc889c1dadb1e4da1b37357b3ef6bf9 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 21 Dec 2016 13:58:57 -0600 Subject: [PATCH 015/119] move scripts around. hide unnecessary stuff. more UI tweaks. --- 02 - JS + CSS Clock/countdown.js | 68 +++++--------------------------- 02 - JS + CSS Clock/digital.css | 22 ++++++----- 02 - JS + CSS Clock/time-diff.js | 42 ++++++++++++++++++++ 02 - JS + CSS Clock/utils.js | 4 ++ 4 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 02 - JS + CSS Clock/time-diff.js diff --git a/02 - JS + CSS Clock/countdown.js b/02 - JS + CSS Clock/countdown.js index b8f326bfbd..1f4ae35df0 100644 --- a/02 - JS + CSS Clock/countdown.js +++ b/02 - JS + CSS Clock/countdown.js @@ -5,13 +5,12 @@ const defTimeArr = defTime.split("T"); // console.log('defTimeArr: ', defTimeArr); - let flagState = ''; + // let flagState = ''; /* cache dome objs */ const grids = document.querySelectorAll(".grid"); const msgFuture = document.querySelectorAll(".future"); const msgPast = document.querySelectorAll(".past"); - const counts = document.querySelectorAll(".count-yrs, .count-mon, .count-day"); const yrs = document.querySelector(".count-yrs"); @@ -29,8 +28,8 @@ const elThen = document.querySelector("#then"); const elThenOffset = document.querySelector("#thenOffset"); - const elThenDate2 = document.querySelector("#then-date2"); - const elThenTime2 = document.querySelector("#then-time2"); + // const elThenDate2 = document.querySelector("#then-date2"); + // const elThenTime2 = document.querySelector("#then-time2"); elThen.value = defTime; // elThenDate2.value = defTimeArr[0]; @@ -103,24 +102,22 @@ if (linkEdit) { if (milliseconds > 0) { // the "then" date is in the future - console.log('future'); - flagState = 'future'; + // console.log('future'); + // flagState = 'future'; msgPast.forEach(msg => msg.classList.add('hi')); msgFuture.forEach(msg => msg.classList.remove('hi')); } else if (milliseconds < 0) { // the "then" date is in the past - console.log('past'); - flagState = 'past'; + // console.log('past'); + // flagState = 'past'; msgPast.forEach(msg => msg.classList.remove('hi')); msgFuture.forEach(msg => msg.classList.add('hi')); } else { // the "then" date is in the present - console.log('present'); - flagState = 'present'; + // console.log('present'); + // flagState = 'present'; } - // timeDiff(milliseconds); - }; function timePrint (then,now) { @@ -181,53 +178,6 @@ if (linkEdit) { }; - function timeDiff (time) { - - var seconds = Math.abs(time)/1000; - console.log('seconds: ', seconds); - - // function numberEnding (number) { - // return (number > 1) ? 's' : ''; - // } - - var temp = Math.floor(seconds); - // console.log('temp: ', temp); - - var numYears = Math.floor(temp / units.years); - // console.log('numYears: ', numYears); - yrs.innerHTML = pad(numYears, 2); - - //TODO: Months! Maybe weeks? - var numMonths = Math.floor((temp %= units.years) / units.months); - // console.log('numMonths: ', numMonths); - mon.innerHTML = pad(numMonths, 2); - - var numDays = Math.floor((temp %= units.months) / units.days); - // console.log('numDays: ', numDays); - day.innerHTML = pad(numDays, 2); - - var numHours = Math.floor((temp %= units.days) / units.hours); - // console.log('numHours: ', numHours); - hrs.innerHTML = pad(numHours, 2); - - var numMinutes = Math.floor((temp %= units.hours) / units.minutes); - // console.log('numMinutes: ', numMinutes); - min.innerHTML = pad(numMinutes, 2); - - var numSeconds = Math.floor(temp % units.minutes); - // console.log('numSeconds: ', numSeconds); - sec.innerHTML = pad(numSeconds, 2); - - hideZeroes(counts); - - // console.log( numYears + " years " + numMonths + " Months " + numDays + " days " + numHours + " hours " + numMinutes + " minutes " + numSeconds + " seconds" ); - - }; - - function hideZeroes (things) { - things.forEach(thing => {if (thing.innerHTML === '00') {thing.style.display = 'none'} else {thing.style.display = 'inline'}}); - } - timeUpdate(); setInterval(timeUpdate, 1000); diff --git a/02 - JS + CSS Clock/digital.css b/02 - JS + CSS Clock/digital.css index a289424e34..e843e3bb2a 100644 --- a/02 - JS + CSS Clock/digital.css +++ b/02 - JS + CSS Clock/digital.css @@ -1,4 +1,4 @@ -/* analog.css */ +/* digital.css */ *, *:before, *:after {padding:0;margin:0;text-align:left;} @@ -80,12 +80,12 @@ input, button, textarea, select { padding:0.25rem; position:relative; text-align:left; + min-width: 540px; } - .clock { display:block; - margin:0.125rem 0 0; + /* margin:0.125rem 0 0; */ font-size:2rem; line-height:1; white-space:normal; @@ -98,12 +98,16 @@ input, button, textarea, select { input.clock {padding:0.5em 0;} ul.clock {padding:0.75em 1rem;} +.clock-now .clock+.clock:nth-of-type(2n+2) {background-color: rgb(51,0,0);} +.clock-then .clock+.clock:nth-of-type(2n+2) {background-color: rgb(0,51,0);} +.clock-delta .clock+.clock:nth-of-type(2n+2) {background-color: rgb(0,27,51);} + .time { display:inline; } -.time-day {font-size:1.4em;} -.time-yrs, .time-mon, .time-dat {font-size:1.2em;} -.time-hrs, .time-min, .time-sec {font-size:1.6em;} +.time-day {font-size:1.2em;} +.time-yrs, .time-mon, .time-dat {} +.time-hrs, .time-min, .time-sec {font-size:1.4em;} .time-yrs:after, .time-mon:after {content:"-";} .time-day:after, .time-dat:after {content:"\a";white-space:pre;} @@ -113,17 +117,17 @@ ul.clock {padding:0.75em 1rem;} .now, .clock-now .clock, .clock-now .display, -.clock-now .timezone {color:rgb(204,51,51);} +.clock-now .timezone {color:rgb(204,51,51);} /* red */ .then, .clock-then .clock, .clock-then .display, -.clock-then .timezone {color:rgb(51,153,51);} +.clock-then .timezone {color:rgb(51,153,51);} /* green */ .delta, .clock-delta .clock, .clock-delta .display, -.clock-delta .timezone {color:rgb(51,153,204);} +.clock-delta .timezone {color:rgb(51,153,204);} /* blue */ .hi { background-color:#111; diff --git a/02 - JS + CSS Clock/time-diff.js b/02 - JS + CSS Clock/time-diff.js new file mode 100644 index 0000000000..16a73d35cb --- /dev/null +++ b/02 - JS + CSS Clock/time-diff.js @@ -0,0 +1,42 @@ +function timeDiff (time) { + + var seconds = Math.abs(time)/1000; + console.log('seconds: ', seconds); + + // function numberEnding (number) { + // return (number > 1) ? 's' : ''; + // } + + var temp = Math.floor(seconds); + // console.log('temp: ', temp); + + var numYears = Math.floor(temp / units.years); + // console.log('numYears: ', numYears); + yrs.innerHTML = pad(numYears, 2); + + //TODO: Months! Maybe weeks? + var numMonths = Math.floor((temp %= units.years) / units.months); + // console.log('numMonths: ', numMonths); + mon.innerHTML = pad(numMonths, 2); + + var numDays = Math.floor((temp %= units.months) / units.days); + // console.log('numDays: ', numDays); + day.innerHTML = pad(numDays, 2); + + var numHours = Math.floor((temp %= units.days) / units.hours); + // console.log('numHours: ', numHours); + hrs.innerHTML = pad(numHours, 2); + + var numMinutes = Math.floor((temp %= units.hours) / units.minutes); + // console.log('numMinutes: ', numMinutes); + min.innerHTML = pad(numMinutes, 2); + + var numSeconds = Math.floor(temp % units.minutes); + // console.log('numSeconds: ', numSeconds); + sec.innerHTML = pad(numSeconds, 2); + + hideZeroes(counts); + + // console.log( numYears + " years " + numMonths + " Months " + numDays + " days " + numHours + " hours " + numMinutes + " minutes " + numSeconds + " seconds" ); + +}; diff --git a/02 - JS + CSS Clock/utils.js b/02 - JS + CSS Clock/utils.js index 4b3b17e889..f7b9a6bb46 100644 --- a/02 - JS + CSS Clock/utils.js +++ b/02 - JS + CSS Clock/utils.js @@ -83,3 +83,7 @@ function timezoneOffset (time, el) { console.log('el.tagName error!'); } } + +function hideZeroes (things) { + things.forEach(thing => {if (thing.innerHTML === '00') {thing.style.display = 'none'} else {thing.style.display = 'inline'}}); +} From 14681512ce294ed8e44219a4a8f2f4a4eefc62dd Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 21 Dec 2016 16:17:38 -0600 Subject: [PATCH 016/119] do some array cardio. --- 04 - Array Cardio Day 1/index-jds.html | 158 +++++++++++++++++++++++++ 04 - Array Cardio Day 1/index.html | 16 +++ index.html | 2 +- 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 04 - Array Cardio Day 1/index-jds.html create mode 100755 04 - Array Cardio Day 1/index.html diff --git a/04 - Array Cardio Day 1/index-jds.html b/04 - Array Cardio Day 1/index-jds.html new file mode 100644 index 0000000000..3473329f82 --- /dev/null +++ b/04 - Array Cardio Day 1/index-jds.html @@ -0,0 +1,158 @@ + + + + + Array Cardio 💪 + + +

    Psst: have a look at the JavaScript Console 💁

    + + + + + + diff --git a/04 - Array Cardio Day 1/index.html b/04 - Array Cardio Day 1/index.html new file mode 100755 index 0000000000..1fa7d3df1d --- /dev/null +++ b/04 - Array Cardio Day 1/index.html @@ -0,0 +1,16 @@ + + + + + Array Cardio 💪 + + + + + + + diff --git a/index.html b/index.html index acb001182b..987aa7cb60 100755 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@
  • 01 - JavaScript Drum Kit
  • 02 - JS + CSS Clock
  • 03 - CSS Variables
  • - +
  • 04 - Array Cardio Day 1
  • From 057ac84ab03fde135708f95200ee2c811b039ed8 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 22 Dec 2016 10:44:49 -0600 Subject: [PATCH 017/119] make array cardio page pretty. unhide project #5 pages. --- 04 - Array Cardio Day 1/index-jds.html | 23 +++-- 05 - Flex Panel Gallery/index-jds.html | 116 +++++++++++++++++++++++++ 05 - Flex Panel Gallery/index.html | 16 ++++ index.html | 2 +- 4 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 05 - Flex Panel Gallery/index-jds.html create mode 100644 05 - Flex Panel Gallery/index.html diff --git a/04 - Array Cardio Day 1/index-jds.html b/04 - Array Cardio Day 1/index-jds.html index 3473329f82..db80f6a828 100644 --- a/04 - Array Cardio Day 1/index-jds.html +++ b/04 - Array Cardio Day 1/index-jds.html @@ -3,6 +3,9 @@ Array Cardio 💪 +

    Psst: have a look at the JavaScript Console 💁

    @@ -74,7 +77,7 @@ // Array.prototype.filter() // 1. Filter the list of inventors for those who were born in the 1500's const inventorsC16 = inventors.filter(obj => (obj.year > 1499 && obj.year < 1600)); - console.group('inventorsC16'); + console.group('1. Array.prototype.filter()'); console.table(inventorsC16); console.groupEnd(); @@ -82,7 +85,9 @@ // 2. Give us an array of the inventors' first and last names // const inventorsNames = inventors.map(obj => obj.first +' '+ obj.last); const inventorsNames = inventors.map(obj => `${obj.first} ${obj.last}`); - console.log('inventorsNames: ', inventorsNames); + console.group('2. Array.prototype.map()'); + console.log(inventorsNames); + console.groupEnd(); // Array.prototype.sort() // 3. Sort the inventors by birthdate, oldest to youngest @@ -94,7 +99,7 @@ // } // }); const inventorsBornFirst = inventors.sort((a,b) => a.year > b.year ? 1 : -1); - console.group('inventorsBornFirst'); + console.group('3. Array.prototype.sort()'); console.table(inventorsBornFirst); console.groupEnd(); @@ -103,7 +108,9 @@ const inventorsLifespan = inventors.reduce((total, inventor) => { return total + (inventor.passed - inventor.year); }, 0); - console.log('inventorsLifespan: ', inventorsLifespan); + console.group('4. Array.prototype.reduce()'); + console.log(inventorsLifespan); + console.groupEnd(); // 5. Sort the inventors by years lived const inventorsSeniority = inventors.sort((a,b) => { @@ -111,7 +118,7 @@ const nextOne = b.passed - b.year; return lastOne > nextOne ? -1 : 1; }); - console.group('inventorsSeniority'); + console.group('5. inventorsSeniority'); console.table(inventorsSeniority); console.groupEnd(); @@ -120,6 +127,7 @@ const city = document.querySelector('.mw-category'); // const streets = [].slice.call(city.querySelectorAll('a')); const streets = Array.from(city.querySelectorAll('a')); + console.group('6. Boulevards in Paris'); console.log(streets); // const deStreets = streets.filter(obj => obj.innerHTML.indexOf('de') > -1); const deStreets = streets @@ -127,6 +135,7 @@ // .filter(obj => obj.indexOf('de') > -1); .filter(obj => obj.includes('de')); console.log(deStreets); + console.groupEnd(); // 7. sort Exercise @@ -138,7 +147,9 @@ // console.log(bLast, bFirst); return aLast > bLast ? 1 : -1; }); + console.group('7. Sort Exercise'); console.log(pplSorted); + console.groupEnd(); // 8. Reduce Exercise // Sum up the instances of each of these @@ -151,7 +162,9 @@ obj[item]++; return obj; }, {}); + console.group('8. Reduce Exercise'); console.log(instances); + console.groupEnd(); diff --git a/05 - Flex Panel Gallery/index-jds.html b/05 - Flex Panel Gallery/index-jds.html new file mode 100644 index 0000000000..e1d643ad5c --- /dev/null +++ b/05 - Flex Panel Gallery/index-jds.html @@ -0,0 +1,116 @@ + + + + + Flex Panels 💪 + + + + + + +
    +
    +

    Hey

    +

    Let's

    +

    Dance

    +
    +
    +

    Give

    +

    Take

    +

    Receive

    +
    +
    +

    Experience

    +

    It

    +

    Today

    +
    +
    +

    Give

    +

    All

    +

    You can

    +
    +
    +

    Life

    +

    In

    +

    Motion

    +
    +
    + + + + + + + diff --git a/05 - Flex Panel Gallery/index.html b/05 - Flex Panel Gallery/index.html new file mode 100644 index 0000000000..2c897f3de5 --- /dev/null +++ b/05 - Flex Panel Gallery/index.html @@ -0,0 +1,16 @@ + + + + + Flex Panels 💪 + + + + + + + diff --git a/index.html b/index.html index 987aa7cb60..76bdb7c73a 100755 --- a/index.html +++ b/index.html @@ -11,7 +11,7 @@
  • 02 - JS + CSS Clock
  • 03 - CSS Variables
  • 04 - Array Cardio Day 1
  • - +
  • 05 - Flex Panel Gallery
  • From 97d80c36ba1eec32e48a075de1f2f9d829580f22 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 22 Dec 2016 11:19:45 -0600 Subject: [PATCH 018/119] clean up file & dir names. --- .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-jds.html | 0 .../index.html | 0 .../sounds/boom.wav | Bin .../sounds/clap.wav | Bin .../sounds/hihat.wav | Bin .../sounds/kick.wav | Bin .../sounds/openhat.wav | Bin .../sounds/ride.wav | Bin .../sounds/snare.wav | Bin .../sounds/tink.wav | Bin .../sounds/tom.wav | Bin .../style.css | 0 .../README.MD | 0 .../analog.css | 0 .../brushed-steel.jpg | Bin .../bttf--time_circuits.png | Bin .../bttf.css | 0 .../countdown.css | 0 .../countdown.js | 0 .../digital.css | 0 .../digital.js | 0 .../grid.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-jds-countdown.html | 0 .../index-jds-digital.html | 0 .../index-jds.html | 0 .../index.html | 0 .../time-diff.js | 0 .../utils.js | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-jds.html | 0 .../index.html | 0 .../photo.jpg | Bin .../style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-jds.html | 0 .../index.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-jds.html | 0 .../index.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 {06 - Type Ahead => 06--Type_Ahead}/style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index.html | 0 .../scripts-FINISHED.js | 0 .../scripts.js | 0 .../style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style.css | 0 .../index-finished.html | 0 .../index-start.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index.html | 0 .../package.json | 0 .../scripts-FINISHED.js | 0 .../scripts.js | 0 {19 - Webcam Fun => 19--Webcam_Fun}/style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../package.json | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../package.json | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style-FINISHED.css | 0 .../style-START.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style.css | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../style.css | 0 .../index.html | 0 .../scripts-FINISHED.js | 0 .../scripts-START.js | 0 .../style.css | 0 .../dirt.svg | 0 .../index-FINISHED.html | 0 .../index-START.html | 0 .../mole.svg | 0 .../style.css | 0 index.html | 60 +++++++++--------- 117 files changed, 30 insertions(+), 30 deletions(-) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/index-FINISHED.html (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/index-START.html (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/index-jds.html (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/index.html (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/boom.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/clap.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/hihat.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/kick.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/openhat.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/ride.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/snare.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/tink.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/sounds/tom.wav (100%) rename {01 - JavaScript Drum Kit => 01--JavaScript_Drum_Kit}/style.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/README.MD (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/analog.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/brushed-steel.jpg (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/bttf--time_circuits.png (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/bttf.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/countdown.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/countdown.js (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/digital.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/digital.js (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/grid.css (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index-FINISHED.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index-START.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index-jds-countdown.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index-jds-digital.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index-jds.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/index.html (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/time-diff.js (100%) rename {02 - JS + CSS Clock => 02--JS_CSS_Clock}/utils.js (100%) rename {03 - CSS Variables => 03--CSS_Variables}/index-FINISHED.html (100%) rename {03 - CSS Variables => 03--CSS_Variables}/index-START.html (100%) rename {03 - CSS Variables => 03--CSS_Variables}/index-jds.html (100%) rename {03 - CSS Variables => 03--CSS_Variables}/index.html (100%) rename {03 - CSS Variables => 03--CSS_Variables}/photo.jpg (100%) rename {03 - CSS Variables => 03--CSS_Variables}/style.css (100%) rename {04 - Array Cardio Day 1 => 04--Array_Cardio_Day_1}/index-FINISHED.html (100%) rename {04 - Array Cardio Day 1 => 04--Array_Cardio_Day_1}/index-START.html (100%) rename {04 - Array Cardio Day 1 => 04--Array_Cardio_Day_1}/index-jds.html (100%) rename {04 - Array Cardio Day 1 => 04--Array_Cardio_Day_1}/index.html (100%) rename {05 - Flex Panel Gallery => 05--Flex_Panel_Gallery}/index-FINISHED.html (100%) rename {05 - Flex Panel Gallery => 05--Flex_Panel_Gallery}/index-START.html (100%) rename {05 - Flex Panel Gallery => 05--Flex_Panel_Gallery}/index-jds.html (100%) rename {05 - Flex Panel Gallery => 05--Flex_Panel_Gallery}/index.html (100%) rename {06 - Type Ahead => 06--Type_Ahead}/index-FINISHED.html (100%) rename {06 - Type Ahead => 06--Type_Ahead}/index-START.html (100%) rename {06 - Type Ahead => 06--Type_Ahead}/style.css (100%) rename {07 - Array Cardio Day 2 => 07--Array_Cardio_Day_2}/index-FINISHED.html (100%) rename {07 - Array Cardio Day 2 => 07--Array_Cardio_Day_2}/index-START.html (100%) rename {08 - Fun with HTML5 Canvas => 08--Fun_with_HTML5_Canvas}/index-FINISHED.html (100%) rename {08 - Fun with HTML5 Canvas => 08--Fun_with_HTML5_Canvas}/index-START.html (100%) rename {09 - Dev Tools Domination => 09--Dev_Tools_Domination}/index-FINISHED.html (100%) rename {09 - Dev Tools Domination => 09--Dev_Tools_Domination}/index-START.html (100%) rename {10 - Hold Shift and Check Checkboxes => 10--Hold_Shift_and_Check_Checkboxes}/index-FINISHED.html (100%) rename {10 - Hold Shift and Check Checkboxes => 10--Hold_Shift_and_Check_Checkboxes}/index-START.html (100%) rename {11 - Custom Video Player => 11--Custom_Video_Player}/index.html (100%) rename {11 - Custom Video Player => 11--Custom_Video_Player}/scripts-FINISHED.js (100%) rename {11 - Custom Video Player => 11--Custom_Video_Player}/scripts.js (100%) rename {11 - Custom Video Player => 11--Custom_Video_Player}/style.css (100%) rename {12 - Key Sequence Detection => 12--Key_Sequence_Detection}/index-FINISHED.html (100%) rename {12 - Key Sequence Detection => 12--Key_Sequence_Detection}/index-START.html (100%) rename {13 - Slide in on Scroll => 13--Slide_in_on_Scroll}/index-FINISHED.html (100%) rename {13 - Slide in on Scroll => 13--Slide_in_on_Scroll}/index-START.html (100%) rename {14 - JavaScript References VS Copying => 14--JavaScript_References_VS_Copying}/index-FINISHED.html (100%) rename {14 - JavaScript References VS Copying => 14--JavaScript_References_VS_Copying}/index-START.html (100%) rename {15 - LocalStorage => 15--LocalStorage}/index-FINISHED.html (100%) rename {15 - LocalStorage => 15--LocalStorage}/index-START.html (100%) rename {15 - LocalStorage => 15--LocalStorage}/style.css (100%) rename {16 - Mouse Move Shadow => 16--Mouse_Move_Shadow}/index-finished.html (100%) rename {16 - Mouse Move Shadow => 16--Mouse_Move_Shadow}/index-start.html (100%) rename {17 - Sort Without Articles => 17--Sort_Without_Articles}/index-FINISHED.html (100%) rename {17 - Sort Without Articles => 17--Sort_Without_Articles}/index-START.html (100%) rename {18 - Adding Up Times with Reduce => 18--Adding_Up_Times_with_Reduce}/index-FINISHED.html (100%) rename {18 - Adding Up Times with Reduce => 18--Adding_Up_Times_with_Reduce}/index-START.html (100%) rename {19 - Webcam Fun => 19--Webcam_Fun}/index.html (100%) rename {19 - Webcam Fun => 19--Webcam_Fun}/package.json (100%) rename {19 - Webcam Fun => 19--Webcam_Fun}/scripts-FINISHED.js (100%) rename {19 - Webcam Fun => 19--Webcam_Fun}/scripts.js (100%) rename {19 - Webcam Fun => 19--Webcam_Fun}/style.css (100%) rename {20 - Speech Detection => 20--Speech_Detection}/index-FINISHED.html (100%) rename {20 - Speech Detection => 20--Speech_Detection}/index-START.html (100%) rename {20 - Speech Detection => 20--Speech_Detection}/package.json (100%) rename {21 - Geolocation => 21--Geolocation}/index-FINISHED.html (100%) rename {21 - Geolocation => 21--Geolocation}/index-START.html (100%) rename {21 - Geolocation => 21--Geolocation}/package.json (100%) rename {22 - Follow Along Link Highlighter => 22--Follow_Along_Link_Highlighter}/index-FINISHED.html (100%) rename {22 - Follow Along Link Highlighter => 22--Follow_Along_Link_Highlighter}/index-START.html (100%) rename {22 - Follow Along Link Highlighter => 22--Follow_Along_Link_Highlighter}/style.css (100%) rename {23 - Speech Synthesis => 23--Speech_Synthesis}/index-FINISHED.html (100%) rename {23 - Speech Synthesis => 23--Speech_Synthesis}/index-START.html (100%) rename {23 - Speech Synthesis => 23--Speech_Synthesis}/style.css (100%) rename {24 - Sticky Nav => 24--Sticky_Nav}/index-FINISHED.html (100%) rename {24 - Sticky Nav => 24--Sticky_Nav}/index-START.html (100%) rename {24 - Sticky Nav => 24--Sticky_Nav}/style-FINISHED.css (100%) rename {24 - Sticky Nav => 24--Sticky_Nav}/style-START.css (100%) rename {25 - Event Capture, Propagation, Bubbling and Once => 25--Event_Capture_Propagation_Bubbling_and_Once}/index-FINISHED.html (100%) rename {25 - Event Capture, Propagation, Bubbling and Once => 25--Event_Capture_Propagation_Bubbling_and_Once}/index-START.html (100%) rename {26 - Stripe Follow Along Nav => 26--Stripe_Follow_Along_Nav}/index-FINISHED.html (100%) rename {26 - Stripe Follow Along Nav => 26--Stripe_Follow_Along_Nav}/index-START.html (100%) rename {27 - Click and Drag => 27--Click_and_Drag}/index-FINISHED.html (100%) rename {27 - Click and Drag => 27--Click_and_Drag}/index-START.html (100%) rename {27 - Click and Drag => 27--Click_and_Drag}/style.css (100%) rename {28 - Video Speed Controller => 28--Video_Speed_Controller}/index-FINISHED.html (100%) rename {28 - Video Speed Controller => 28--Video_Speed_Controller}/index-START.html (100%) rename {28 - Video Speed Controller => 28--Video_Speed_Controller}/style.css (100%) rename {29 - Countdown Timer => 29--Countdown_Timer}/index.html (100%) rename {29 - Countdown Timer => 29--Countdown_Timer}/scripts-FINISHED.js (100%) rename {29 - Countdown Timer => 29--Countdown_Timer}/scripts-START.js (100%) rename {29 - Countdown Timer => 29--Countdown_Timer}/style.css (100%) rename {30 - Whack A Mole => 30--Whack_A_Mole}/dirt.svg (100%) rename {30 - Whack A Mole => 30--Whack_A_Mole}/index-FINISHED.html (100%) rename {30 - Whack A Mole => 30--Whack_A_Mole}/index-START.html (100%) rename {30 - Whack A Mole => 30--Whack_A_Mole}/mole.svg (100%) rename {30 - Whack A Mole => 30--Whack_A_Mole}/style.css (100%) diff --git a/01 - JavaScript Drum Kit/index-FINISHED.html b/01--JavaScript_Drum_Kit/index-FINISHED.html similarity index 100% rename from 01 - JavaScript Drum Kit/index-FINISHED.html rename to 01--JavaScript_Drum_Kit/index-FINISHED.html diff --git a/01 - JavaScript Drum Kit/index-START.html b/01--JavaScript_Drum_Kit/index-START.html similarity index 100% rename from 01 - JavaScript Drum Kit/index-START.html rename to 01--JavaScript_Drum_Kit/index-START.html diff --git a/01 - JavaScript Drum Kit/index-jds.html b/01--JavaScript_Drum_Kit/index-jds.html similarity index 100% rename from 01 - JavaScript Drum Kit/index-jds.html rename to 01--JavaScript_Drum_Kit/index-jds.html diff --git a/01 - JavaScript Drum Kit/index.html b/01--JavaScript_Drum_Kit/index.html similarity index 100% rename from 01 - JavaScript Drum Kit/index.html rename to 01--JavaScript_Drum_Kit/index.html diff --git a/01 - JavaScript Drum Kit/sounds/boom.wav b/01--JavaScript_Drum_Kit/sounds/boom.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/boom.wav rename to 01--JavaScript_Drum_Kit/sounds/boom.wav diff --git a/01 - JavaScript Drum Kit/sounds/clap.wav b/01--JavaScript_Drum_Kit/sounds/clap.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/clap.wav rename to 01--JavaScript_Drum_Kit/sounds/clap.wav diff --git a/01 - JavaScript Drum Kit/sounds/hihat.wav b/01--JavaScript_Drum_Kit/sounds/hihat.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/hihat.wav rename to 01--JavaScript_Drum_Kit/sounds/hihat.wav diff --git a/01 - JavaScript Drum Kit/sounds/kick.wav b/01--JavaScript_Drum_Kit/sounds/kick.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/kick.wav rename to 01--JavaScript_Drum_Kit/sounds/kick.wav diff --git a/01 - JavaScript Drum Kit/sounds/openhat.wav b/01--JavaScript_Drum_Kit/sounds/openhat.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/openhat.wav rename to 01--JavaScript_Drum_Kit/sounds/openhat.wav diff --git a/01 - JavaScript Drum Kit/sounds/ride.wav b/01--JavaScript_Drum_Kit/sounds/ride.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/ride.wav rename to 01--JavaScript_Drum_Kit/sounds/ride.wav diff --git a/01 - JavaScript Drum Kit/sounds/snare.wav b/01--JavaScript_Drum_Kit/sounds/snare.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/snare.wav rename to 01--JavaScript_Drum_Kit/sounds/snare.wav diff --git a/01 - JavaScript Drum Kit/sounds/tink.wav b/01--JavaScript_Drum_Kit/sounds/tink.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/tink.wav rename to 01--JavaScript_Drum_Kit/sounds/tink.wav diff --git a/01 - JavaScript Drum Kit/sounds/tom.wav b/01--JavaScript_Drum_Kit/sounds/tom.wav similarity index 100% rename from 01 - JavaScript Drum Kit/sounds/tom.wav rename to 01--JavaScript_Drum_Kit/sounds/tom.wav diff --git a/01 - JavaScript Drum Kit/style.css b/01--JavaScript_Drum_Kit/style.css similarity index 100% rename from 01 - JavaScript Drum Kit/style.css rename to 01--JavaScript_Drum_Kit/style.css diff --git a/02 - JS + CSS Clock/README.MD b/02--JS_CSS_Clock/README.MD similarity index 100% rename from 02 - JS + CSS Clock/README.MD rename to 02--JS_CSS_Clock/README.MD diff --git a/02 - JS + CSS Clock/analog.css b/02--JS_CSS_Clock/analog.css similarity index 100% rename from 02 - JS + CSS Clock/analog.css rename to 02--JS_CSS_Clock/analog.css diff --git a/02 - JS + CSS Clock/brushed-steel.jpg b/02--JS_CSS_Clock/brushed-steel.jpg similarity index 100% rename from 02 - JS + CSS Clock/brushed-steel.jpg rename to 02--JS_CSS_Clock/brushed-steel.jpg diff --git a/02 - JS + CSS Clock/bttf--time_circuits.png b/02--JS_CSS_Clock/bttf--time_circuits.png similarity index 100% rename from 02 - JS + CSS Clock/bttf--time_circuits.png rename to 02--JS_CSS_Clock/bttf--time_circuits.png diff --git a/02 - JS + CSS Clock/bttf.css b/02--JS_CSS_Clock/bttf.css similarity index 100% rename from 02 - JS + CSS Clock/bttf.css rename to 02--JS_CSS_Clock/bttf.css diff --git a/02 - JS + CSS Clock/countdown.css b/02--JS_CSS_Clock/countdown.css similarity index 100% rename from 02 - JS + CSS Clock/countdown.css rename to 02--JS_CSS_Clock/countdown.css diff --git a/02 - JS + CSS Clock/countdown.js b/02--JS_CSS_Clock/countdown.js similarity index 100% rename from 02 - JS + CSS Clock/countdown.js rename to 02--JS_CSS_Clock/countdown.js diff --git a/02 - JS + CSS Clock/digital.css b/02--JS_CSS_Clock/digital.css similarity index 100% rename from 02 - JS + CSS Clock/digital.css rename to 02--JS_CSS_Clock/digital.css diff --git a/02 - JS + CSS Clock/digital.js b/02--JS_CSS_Clock/digital.js similarity index 100% rename from 02 - JS + CSS Clock/digital.js rename to 02--JS_CSS_Clock/digital.js diff --git a/02 - JS + CSS Clock/grid.css b/02--JS_CSS_Clock/grid.css similarity index 100% rename from 02 - JS + CSS Clock/grid.css rename to 02--JS_CSS_Clock/grid.css diff --git a/02 - JS + CSS Clock/index-FINISHED.html b/02--JS_CSS_Clock/index-FINISHED.html similarity index 100% rename from 02 - JS + CSS Clock/index-FINISHED.html rename to 02--JS_CSS_Clock/index-FINISHED.html diff --git a/02 - JS + CSS Clock/index-START.html b/02--JS_CSS_Clock/index-START.html similarity index 100% rename from 02 - JS + CSS Clock/index-START.html rename to 02--JS_CSS_Clock/index-START.html diff --git a/02 - JS + CSS Clock/index-jds-countdown.html b/02--JS_CSS_Clock/index-jds-countdown.html similarity index 100% rename from 02 - JS + CSS Clock/index-jds-countdown.html rename to 02--JS_CSS_Clock/index-jds-countdown.html diff --git a/02 - JS + CSS Clock/index-jds-digital.html b/02--JS_CSS_Clock/index-jds-digital.html similarity index 100% rename from 02 - JS + CSS Clock/index-jds-digital.html rename to 02--JS_CSS_Clock/index-jds-digital.html diff --git a/02 - JS + CSS Clock/index-jds.html b/02--JS_CSS_Clock/index-jds.html similarity index 100% rename from 02 - JS + CSS Clock/index-jds.html rename to 02--JS_CSS_Clock/index-jds.html diff --git a/02 - JS + CSS Clock/index.html b/02--JS_CSS_Clock/index.html similarity index 100% rename from 02 - JS + CSS Clock/index.html rename to 02--JS_CSS_Clock/index.html diff --git a/02 - JS + CSS Clock/time-diff.js b/02--JS_CSS_Clock/time-diff.js similarity index 100% rename from 02 - JS + CSS Clock/time-diff.js rename to 02--JS_CSS_Clock/time-diff.js diff --git a/02 - JS + CSS Clock/utils.js b/02--JS_CSS_Clock/utils.js similarity index 100% rename from 02 - JS + CSS Clock/utils.js rename to 02--JS_CSS_Clock/utils.js diff --git a/03 - CSS Variables/index-FINISHED.html b/03--CSS_Variables/index-FINISHED.html similarity index 100% rename from 03 - CSS Variables/index-FINISHED.html rename to 03--CSS_Variables/index-FINISHED.html diff --git a/03 - CSS Variables/index-START.html b/03--CSS_Variables/index-START.html similarity index 100% rename from 03 - CSS Variables/index-START.html rename to 03--CSS_Variables/index-START.html diff --git a/03 - CSS Variables/index-jds.html b/03--CSS_Variables/index-jds.html similarity index 100% rename from 03 - CSS Variables/index-jds.html rename to 03--CSS_Variables/index-jds.html diff --git a/03 - CSS Variables/index.html b/03--CSS_Variables/index.html similarity index 100% rename from 03 - CSS Variables/index.html rename to 03--CSS_Variables/index.html diff --git a/03 - CSS Variables/photo.jpg b/03--CSS_Variables/photo.jpg similarity index 100% rename from 03 - CSS Variables/photo.jpg rename to 03--CSS_Variables/photo.jpg diff --git a/03 - CSS Variables/style.css b/03--CSS_Variables/style.css similarity index 100% rename from 03 - CSS Variables/style.css rename to 03--CSS_Variables/style.css diff --git a/04 - Array Cardio Day 1/index-FINISHED.html b/04--Array_Cardio_Day_1/index-FINISHED.html similarity index 100% rename from 04 - Array Cardio Day 1/index-FINISHED.html rename to 04--Array_Cardio_Day_1/index-FINISHED.html diff --git a/04 - Array Cardio Day 1/index-START.html b/04--Array_Cardio_Day_1/index-START.html similarity index 100% rename from 04 - Array Cardio Day 1/index-START.html rename to 04--Array_Cardio_Day_1/index-START.html diff --git a/04 - Array Cardio Day 1/index-jds.html b/04--Array_Cardio_Day_1/index-jds.html similarity index 100% rename from 04 - Array Cardio Day 1/index-jds.html rename to 04--Array_Cardio_Day_1/index-jds.html diff --git a/04 - Array Cardio Day 1/index.html b/04--Array_Cardio_Day_1/index.html similarity index 100% rename from 04 - Array Cardio Day 1/index.html rename to 04--Array_Cardio_Day_1/index.html diff --git a/05 - Flex Panel Gallery/index-FINISHED.html b/05--Flex_Panel_Gallery/index-FINISHED.html similarity index 100% rename from 05 - Flex Panel Gallery/index-FINISHED.html rename to 05--Flex_Panel_Gallery/index-FINISHED.html diff --git a/05 - Flex Panel Gallery/index-START.html b/05--Flex_Panel_Gallery/index-START.html similarity index 100% rename from 05 - Flex Panel Gallery/index-START.html rename to 05--Flex_Panel_Gallery/index-START.html diff --git a/05 - Flex Panel Gallery/index-jds.html b/05--Flex_Panel_Gallery/index-jds.html similarity index 100% rename from 05 - Flex Panel Gallery/index-jds.html rename to 05--Flex_Panel_Gallery/index-jds.html diff --git a/05 - Flex Panel Gallery/index.html b/05--Flex_Panel_Gallery/index.html similarity index 100% rename from 05 - Flex Panel Gallery/index.html rename to 05--Flex_Panel_Gallery/index.html diff --git a/06 - Type Ahead/index-FINISHED.html b/06--Type_Ahead/index-FINISHED.html similarity index 100% rename from 06 - Type Ahead/index-FINISHED.html rename to 06--Type_Ahead/index-FINISHED.html diff --git a/06 - Type Ahead/index-START.html b/06--Type_Ahead/index-START.html similarity index 100% rename from 06 - Type Ahead/index-START.html rename to 06--Type_Ahead/index-START.html diff --git a/06 - Type Ahead/style.css b/06--Type_Ahead/style.css similarity index 100% rename from 06 - Type Ahead/style.css rename to 06--Type_Ahead/style.css diff --git a/07 - Array Cardio Day 2/index-FINISHED.html b/07--Array_Cardio_Day_2/index-FINISHED.html similarity index 100% rename from 07 - Array Cardio Day 2/index-FINISHED.html rename to 07--Array_Cardio_Day_2/index-FINISHED.html diff --git a/07 - Array Cardio Day 2/index-START.html b/07--Array_Cardio_Day_2/index-START.html similarity index 100% rename from 07 - Array Cardio Day 2/index-START.html rename to 07--Array_Cardio_Day_2/index-START.html diff --git a/08 - Fun with HTML5 Canvas/index-FINISHED.html b/08--Fun_with_HTML5_Canvas/index-FINISHED.html similarity index 100% rename from 08 - Fun with HTML5 Canvas/index-FINISHED.html rename to 08--Fun_with_HTML5_Canvas/index-FINISHED.html diff --git a/08 - Fun with HTML5 Canvas/index-START.html b/08--Fun_with_HTML5_Canvas/index-START.html similarity index 100% rename from 08 - Fun with HTML5 Canvas/index-START.html rename to 08--Fun_with_HTML5_Canvas/index-START.html diff --git a/09 - Dev Tools Domination/index-FINISHED.html b/09--Dev_Tools_Domination/index-FINISHED.html similarity index 100% rename from 09 - Dev Tools Domination/index-FINISHED.html rename to 09--Dev_Tools_Domination/index-FINISHED.html diff --git a/09 - Dev Tools Domination/index-START.html b/09--Dev_Tools_Domination/index-START.html similarity index 100% rename from 09 - Dev Tools Domination/index-START.html rename to 09--Dev_Tools_Domination/index-START.html diff --git a/10 - Hold Shift and Check Checkboxes/index-FINISHED.html b/10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html similarity index 100% rename from 10 - Hold Shift and Check Checkboxes/index-FINISHED.html rename to 10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html diff --git a/10 - Hold Shift and Check Checkboxes/index-START.html b/10--Hold_Shift_and_Check_Checkboxes/index-START.html similarity index 100% rename from 10 - Hold Shift and Check Checkboxes/index-START.html rename to 10--Hold_Shift_and_Check_Checkboxes/index-START.html diff --git a/11 - Custom Video Player/index.html b/11--Custom_Video_Player/index.html similarity index 100% rename from 11 - Custom Video Player/index.html rename to 11--Custom_Video_Player/index.html diff --git a/11 - Custom Video Player/scripts-FINISHED.js b/11--Custom_Video_Player/scripts-FINISHED.js similarity index 100% rename from 11 - Custom Video Player/scripts-FINISHED.js rename to 11--Custom_Video_Player/scripts-FINISHED.js diff --git a/11 - Custom Video Player/scripts.js b/11--Custom_Video_Player/scripts.js similarity index 100% rename from 11 - Custom Video Player/scripts.js rename to 11--Custom_Video_Player/scripts.js diff --git a/11 - Custom Video Player/style.css b/11--Custom_Video_Player/style.css similarity index 100% rename from 11 - Custom Video Player/style.css rename to 11--Custom_Video_Player/style.css diff --git a/12 - Key Sequence Detection/index-FINISHED.html b/12--Key_Sequence_Detection/index-FINISHED.html similarity index 100% rename from 12 - Key Sequence Detection/index-FINISHED.html rename to 12--Key_Sequence_Detection/index-FINISHED.html diff --git a/12 - Key Sequence Detection/index-START.html b/12--Key_Sequence_Detection/index-START.html similarity index 100% rename from 12 - Key Sequence Detection/index-START.html rename to 12--Key_Sequence_Detection/index-START.html diff --git a/13 - Slide in on Scroll/index-FINISHED.html b/13--Slide_in_on_Scroll/index-FINISHED.html similarity index 100% rename from 13 - Slide in on Scroll/index-FINISHED.html rename to 13--Slide_in_on_Scroll/index-FINISHED.html diff --git a/13 - Slide in on Scroll/index-START.html b/13--Slide_in_on_Scroll/index-START.html similarity index 100% rename from 13 - Slide in on Scroll/index-START.html rename to 13--Slide_in_on_Scroll/index-START.html diff --git a/14 - JavaScript References VS Copying/index-FINISHED.html b/14--JavaScript_References_VS_Copying/index-FINISHED.html similarity index 100% rename from 14 - JavaScript References VS Copying/index-FINISHED.html rename to 14--JavaScript_References_VS_Copying/index-FINISHED.html diff --git a/14 - JavaScript References VS Copying/index-START.html b/14--JavaScript_References_VS_Copying/index-START.html similarity index 100% rename from 14 - JavaScript References VS Copying/index-START.html rename to 14--JavaScript_References_VS_Copying/index-START.html diff --git a/15 - LocalStorage/index-FINISHED.html b/15--LocalStorage/index-FINISHED.html similarity index 100% rename from 15 - LocalStorage/index-FINISHED.html rename to 15--LocalStorage/index-FINISHED.html diff --git a/15 - LocalStorage/index-START.html b/15--LocalStorage/index-START.html similarity index 100% rename from 15 - LocalStorage/index-START.html rename to 15--LocalStorage/index-START.html diff --git a/15 - LocalStorage/style.css b/15--LocalStorage/style.css similarity index 100% rename from 15 - LocalStorage/style.css rename to 15--LocalStorage/style.css diff --git a/16 - Mouse Move Shadow/index-finished.html b/16--Mouse_Move_Shadow/index-finished.html similarity index 100% rename from 16 - Mouse Move Shadow/index-finished.html rename to 16--Mouse_Move_Shadow/index-finished.html diff --git a/16 - Mouse Move Shadow/index-start.html b/16--Mouse_Move_Shadow/index-start.html similarity index 100% rename from 16 - Mouse Move Shadow/index-start.html rename to 16--Mouse_Move_Shadow/index-start.html diff --git a/17 - Sort Without Articles/index-FINISHED.html b/17--Sort_Without_Articles/index-FINISHED.html similarity index 100% rename from 17 - Sort Without Articles/index-FINISHED.html rename to 17--Sort_Without_Articles/index-FINISHED.html diff --git a/17 - Sort Without Articles/index-START.html b/17--Sort_Without_Articles/index-START.html similarity index 100% rename from 17 - Sort Without Articles/index-START.html rename to 17--Sort_Without_Articles/index-START.html diff --git a/18 - Adding Up Times with Reduce/index-FINISHED.html b/18--Adding_Up_Times_with_Reduce/index-FINISHED.html similarity index 100% rename from 18 - Adding Up Times with Reduce/index-FINISHED.html rename to 18--Adding_Up_Times_with_Reduce/index-FINISHED.html diff --git a/18 - Adding Up Times with Reduce/index-START.html b/18--Adding_Up_Times_with_Reduce/index-START.html similarity index 100% rename from 18 - Adding Up Times with Reduce/index-START.html rename to 18--Adding_Up_Times_with_Reduce/index-START.html diff --git a/19 - Webcam Fun/index.html b/19--Webcam_Fun/index.html similarity index 100% rename from 19 - Webcam Fun/index.html rename to 19--Webcam_Fun/index.html diff --git a/19 - Webcam Fun/package.json b/19--Webcam_Fun/package.json similarity index 100% rename from 19 - Webcam Fun/package.json rename to 19--Webcam_Fun/package.json diff --git a/19 - Webcam Fun/scripts-FINISHED.js b/19--Webcam_Fun/scripts-FINISHED.js similarity index 100% rename from 19 - Webcam Fun/scripts-FINISHED.js rename to 19--Webcam_Fun/scripts-FINISHED.js diff --git a/19 - Webcam Fun/scripts.js b/19--Webcam_Fun/scripts.js similarity index 100% rename from 19 - Webcam Fun/scripts.js rename to 19--Webcam_Fun/scripts.js diff --git a/19 - Webcam Fun/style.css b/19--Webcam_Fun/style.css similarity index 100% rename from 19 - Webcam Fun/style.css rename to 19--Webcam_Fun/style.css diff --git a/20 - Speech Detection/index-FINISHED.html b/20--Speech_Detection/index-FINISHED.html similarity index 100% rename from 20 - Speech Detection/index-FINISHED.html rename to 20--Speech_Detection/index-FINISHED.html diff --git a/20 - Speech Detection/index-START.html b/20--Speech_Detection/index-START.html similarity index 100% rename from 20 - Speech Detection/index-START.html rename to 20--Speech_Detection/index-START.html diff --git a/20 - Speech Detection/package.json b/20--Speech_Detection/package.json similarity index 100% rename from 20 - Speech Detection/package.json rename to 20--Speech_Detection/package.json diff --git a/21 - Geolocation/index-FINISHED.html b/21--Geolocation/index-FINISHED.html similarity index 100% rename from 21 - Geolocation/index-FINISHED.html rename to 21--Geolocation/index-FINISHED.html diff --git a/21 - Geolocation/index-START.html b/21--Geolocation/index-START.html similarity index 100% rename from 21 - Geolocation/index-START.html rename to 21--Geolocation/index-START.html diff --git a/21 - Geolocation/package.json b/21--Geolocation/package.json similarity index 100% rename from 21 - Geolocation/package.json rename to 21--Geolocation/package.json diff --git a/22 - Follow Along Link Highlighter/index-FINISHED.html b/22--Follow_Along_Link_Highlighter/index-FINISHED.html similarity index 100% rename from 22 - Follow Along Link Highlighter/index-FINISHED.html rename to 22--Follow_Along_Link_Highlighter/index-FINISHED.html diff --git a/22 - Follow Along Link Highlighter/index-START.html b/22--Follow_Along_Link_Highlighter/index-START.html similarity index 100% rename from 22 - Follow Along Link Highlighter/index-START.html rename to 22--Follow_Along_Link_Highlighter/index-START.html diff --git a/22 - Follow Along Link Highlighter/style.css b/22--Follow_Along_Link_Highlighter/style.css similarity index 100% rename from 22 - Follow Along Link Highlighter/style.css rename to 22--Follow_Along_Link_Highlighter/style.css diff --git a/23 - Speech Synthesis/index-FINISHED.html b/23--Speech_Synthesis/index-FINISHED.html similarity index 100% rename from 23 - Speech Synthesis/index-FINISHED.html rename to 23--Speech_Synthesis/index-FINISHED.html diff --git a/23 - Speech Synthesis/index-START.html b/23--Speech_Synthesis/index-START.html similarity index 100% rename from 23 - Speech Synthesis/index-START.html rename to 23--Speech_Synthesis/index-START.html diff --git a/23 - Speech Synthesis/style.css b/23--Speech_Synthesis/style.css similarity index 100% rename from 23 - Speech Synthesis/style.css rename to 23--Speech_Synthesis/style.css diff --git a/24 - Sticky Nav/index-FINISHED.html b/24--Sticky_Nav/index-FINISHED.html similarity index 100% rename from 24 - Sticky Nav/index-FINISHED.html rename to 24--Sticky_Nav/index-FINISHED.html diff --git a/24 - Sticky Nav/index-START.html b/24--Sticky_Nav/index-START.html similarity index 100% rename from 24 - Sticky Nav/index-START.html rename to 24--Sticky_Nav/index-START.html diff --git a/24 - Sticky Nav/style-FINISHED.css b/24--Sticky_Nav/style-FINISHED.css similarity index 100% rename from 24 - Sticky Nav/style-FINISHED.css rename to 24--Sticky_Nav/style-FINISHED.css diff --git a/24 - Sticky Nav/style-START.css b/24--Sticky_Nav/style-START.css similarity index 100% rename from 24 - Sticky Nav/style-START.css rename to 24--Sticky_Nav/style-START.css diff --git a/25 - Event Capture, Propagation, Bubbling and Once/index-FINISHED.html b/25--Event_Capture_Propagation_Bubbling_and_Once/index-FINISHED.html similarity index 100% rename from 25 - Event Capture, Propagation, Bubbling and Once/index-FINISHED.html rename to 25--Event_Capture_Propagation_Bubbling_and_Once/index-FINISHED.html diff --git a/25 - Event Capture, Propagation, Bubbling and Once/index-START.html b/25--Event_Capture_Propagation_Bubbling_and_Once/index-START.html similarity index 100% rename from 25 - Event Capture, Propagation, Bubbling and Once/index-START.html rename to 25--Event_Capture_Propagation_Bubbling_and_Once/index-START.html diff --git a/26 - Stripe Follow Along Nav/index-FINISHED.html b/26--Stripe_Follow_Along_Nav/index-FINISHED.html similarity index 100% rename from 26 - Stripe Follow Along Nav/index-FINISHED.html rename to 26--Stripe_Follow_Along_Nav/index-FINISHED.html diff --git a/26 - Stripe Follow Along Nav/index-START.html b/26--Stripe_Follow_Along_Nav/index-START.html similarity index 100% rename from 26 - Stripe Follow Along Nav/index-START.html rename to 26--Stripe_Follow_Along_Nav/index-START.html diff --git a/27 - Click and Drag/index-FINISHED.html b/27--Click_and_Drag/index-FINISHED.html similarity index 100% rename from 27 - Click and Drag/index-FINISHED.html rename to 27--Click_and_Drag/index-FINISHED.html diff --git a/27 - Click and Drag/index-START.html b/27--Click_and_Drag/index-START.html similarity index 100% rename from 27 - Click and Drag/index-START.html rename to 27--Click_and_Drag/index-START.html diff --git a/27 - Click and Drag/style.css b/27--Click_and_Drag/style.css similarity index 100% rename from 27 - Click and Drag/style.css rename to 27--Click_and_Drag/style.css diff --git a/28 - Video Speed Controller/index-FINISHED.html b/28--Video_Speed_Controller/index-FINISHED.html similarity index 100% rename from 28 - Video Speed Controller/index-FINISHED.html rename to 28--Video_Speed_Controller/index-FINISHED.html diff --git a/28 - Video Speed Controller/index-START.html b/28--Video_Speed_Controller/index-START.html similarity index 100% rename from 28 - Video Speed Controller/index-START.html rename to 28--Video_Speed_Controller/index-START.html diff --git a/28 - Video Speed Controller/style.css b/28--Video_Speed_Controller/style.css similarity index 100% rename from 28 - Video Speed Controller/style.css rename to 28--Video_Speed_Controller/style.css diff --git a/29 - Countdown Timer/index.html b/29--Countdown_Timer/index.html similarity index 100% rename from 29 - Countdown Timer/index.html rename to 29--Countdown_Timer/index.html diff --git a/29 - Countdown Timer/scripts-FINISHED.js b/29--Countdown_Timer/scripts-FINISHED.js similarity index 100% rename from 29 - Countdown Timer/scripts-FINISHED.js rename to 29--Countdown_Timer/scripts-FINISHED.js diff --git a/29 - Countdown Timer/scripts-START.js b/29--Countdown_Timer/scripts-START.js similarity index 100% rename from 29 - Countdown Timer/scripts-START.js rename to 29--Countdown_Timer/scripts-START.js diff --git a/29 - Countdown Timer/style.css b/29--Countdown_Timer/style.css similarity index 100% rename from 29 - Countdown Timer/style.css rename to 29--Countdown_Timer/style.css diff --git a/30 - Whack A Mole/dirt.svg b/30--Whack_A_Mole/dirt.svg similarity index 100% rename from 30 - Whack A Mole/dirt.svg rename to 30--Whack_A_Mole/dirt.svg diff --git a/30 - Whack A Mole/index-FINISHED.html b/30--Whack_A_Mole/index-FINISHED.html similarity index 100% rename from 30 - Whack A Mole/index-FINISHED.html rename to 30--Whack_A_Mole/index-FINISHED.html diff --git a/30 - Whack A Mole/index-START.html b/30--Whack_A_Mole/index-START.html similarity index 100% rename from 30 - Whack A Mole/index-START.html rename to 30--Whack_A_Mole/index-START.html diff --git a/30 - Whack A Mole/mole.svg b/30--Whack_A_Mole/mole.svg similarity index 100% rename from 30 - Whack A Mole/mole.svg rename to 30--Whack_A_Mole/mole.svg diff --git a/30 - Whack A Mole/style.css b/30--Whack_A_Mole/style.css similarity index 100% rename from 30 - Whack A Mole/style.css rename to 30--Whack_A_Mole/style.css diff --git a/index.html b/index.html index 76bdb7c73a..5307277461 100755 --- a/index.html +++ b/index.html @@ -7,36 +7,36 @@ From b7c5b13ed8a9a5ab1b095968ab2b8e2e97cb4758 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 22 Dec 2016 12:19:28 -0600 Subject: [PATCH 019/119] init work on project 5. --- 05--Flex_Panel_Gallery/index-jds.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/05--Flex_Panel_Gallery/index-jds.html b/05--Flex_Panel_Gallery/index-jds.html index e1d643ad5c..5a75b6ee11 100644 --- a/05--Flex_Panel_Gallery/index-jds.html +++ b/05--Flex_Panel_Gallery/index-jds.html @@ -24,6 +24,9 @@ .panels { min-height:100vh; overflow: hidden; + display: flex; + justify-content: space-between; + align-items: stretch; } .panel { @@ -32,6 +35,7 @@ color:white; text-align: center; align-items:center; + flex:1; /* Safari transitionend event.propertyName === flex */ /* Chrome + FF transitionend event.propertyName === flex-grow */ transition: From 8e9c398854799f77fed4244627887380e8cdfd44 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 22 Dec 2016 13:57:31 -0600 Subject: [PATCH 020/119] perfected flex panel gallery... added closeAll functionality. --- 02--JS_CSS_Clock/analog.css | 3 +- 05--Flex_Panel_Gallery/index-jds.html | 112 ++++++++++++++++++-------- 2 files changed, 79 insertions(+), 36 deletions(-) diff --git a/02--JS_CSS_Clock/analog.css b/02--JS_CSS_Clock/analog.css index fac307ef08..26cfd41b35 100644 --- a/02--JS_CSS_Clock/analog.css +++ b/02--JS_CSS_Clock/analog.css @@ -51,8 +51,7 @@ body { top:calc(50% - 3px); transform-origin:100% 3px; transform: rotate(90deg); - transition: all 0.05s; - transition-timing-function: cubic-bezier(0, 1.5, 1, 2); + transition: all 0.05s cubic-bezier(0, 1.5, 1, 2); } .hour-hand { diff --git a/05--Flex_Panel_Gallery/index-jds.html b/05--Flex_Panel_Gallery/index-jds.html index 5a75b6ee11..3d94d9d1b6 100644 --- a/05--Flex_Panel_Gallery/index-jds.html +++ b/05--Flex_Panel_Gallery/index-jds.html @@ -4,14 +4,16 @@ Flex Panels 💪 + + + + diff --git a/07--Array_Cardio_Day_2/index.html b/07--Array_Cardio_Day_2/index.html new file mode 100644 index 0000000000..c1dad0fae2 --- /dev/null +++ b/07--Array_Cardio_Day_2/index.html @@ -0,0 +1,16 @@ + + + + + Array Cardio 💪💪 + + + + + + + diff --git a/index.html b/index.html index 490a8bd46f..1384a1c0bb 100755 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@
  • 04 - Array Cardio Day 1
  • 05 - Flex Panel Gallery
  • 06 - Type Ahead
  • - +
  • 07 - Array Cardio Day 2
  • From 78226ee6f5ca75e3473f361577b5109cd1e30dfb Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 28 Dec 2016 13:22:03 -0600 Subject: [PATCH 027/119] set up project 8. --- 08--Fun_with_HTML5_Canvas/index-jds.html | 19 +++++++++++++++++++ 08--Fun_with_HTML5_Canvas/index.html | 16 ++++++++++++++++ index.html | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 08--Fun_with_HTML5_Canvas/index-jds.html create mode 100644 08--Fun_with_HTML5_Canvas/index.html diff --git a/08--Fun_with_HTML5_Canvas/index-jds.html b/08--Fun_with_HTML5_Canvas/index-jds.html new file mode 100644 index 0000000000..37c148df07 --- /dev/null +++ b/08--Fun_with_HTML5_Canvas/index-jds.html @@ -0,0 +1,19 @@ + + + + + HTML5 Canvas + + + + + + + + + diff --git a/08--Fun_with_HTML5_Canvas/index.html b/08--Fun_with_HTML5_Canvas/index.html new file mode 100644 index 0000000000..567643aac6 --- /dev/null +++ b/08--Fun_with_HTML5_Canvas/index.html @@ -0,0 +1,16 @@ + + + + + HTML5 Canvas + + + + + + + diff --git a/index.html b/index.html index 1384a1c0bb..77e888d11b 100755 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@
  • 05 - Flex Panel Gallery
  • 06 - Type Ahead
  • 07 - Array Cardio Day 2
  • - +
  • 08 - Fun with HTML5 Canvas
  • From a5c7d92f87e0fdccf15f73b747d95feabb7b86d0 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 28 Dec 2016 15:25:02 -0600 Subject: [PATCH 028/119] finish project 8. --- 08--Fun_with_HTML5_Canvas/index-jds.html | 72 +++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/08--Fun_with_HTML5_Canvas/index-jds.html b/08--Fun_with_HTML5_Canvas/index-jds.html index 37c148df07..6abd320cb5 100644 --- a/08--Fun_with_HTML5_Canvas/index-jds.html +++ b/08--Fun_with_HTML5_Canvas/index-jds.html @@ -5,14 +5,82 @@ HTML5 Canvas - + + + fallback content + + From 748f68a0fb7dd04dbe72d3650cfacc778241dbe9 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 28 Dec 2016 15:46:21 -0600 Subject: [PATCH 029/119] do project 9. --- 09--Dev_Tools_Domination/index-jds.html | 80 +++++++++++++++++++++++++ 09--Dev_Tools_Domination/index.html | 16 +++++ index.html | 2 +- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 09--Dev_Tools_Domination/index-jds.html create mode 100644 09--Dev_Tools_Domination/index.html diff --git a/09--Dev_Tools_Domination/index-jds.html b/09--Dev_Tools_Domination/index-jds.html new file mode 100644 index 0000000000..0259b836ab --- /dev/null +++ b/09--Dev_Tools_Domination/index-jds.html @@ -0,0 +1,80 @@ + + + + + Console Tricks! + + + +

    ×BREAK×DOWN×

    + + + + diff --git a/09--Dev_Tools_Domination/index.html b/09--Dev_Tools_Domination/index.html new file mode 100644 index 0000000000..1844c99354 --- /dev/null +++ b/09--Dev_Tools_Domination/index.html @@ -0,0 +1,16 @@ + + + + + Console Tricks! + + + + + + + diff --git a/index.html b/index.html index 77e888d11b..137994032b 100755 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@
  • 06 - Type Ahead
  • 07 - Array Cardio Day 2
  • 08 - Fun with HTML5 Canvas
  • - +
  • 09 - Dev Tools Domination
  • From 32c71c699c442c8a5ec1cbf97c982313d3013419 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 29 Dec 2016 12:52:47 -0600 Subject: [PATCH 030/119] Start work on project 10. --- .../index-FINISHED.html | 56 +---------- .../index-START.html | 56 +---------- .../index-jds.html | 95 +++++++++++++++++++ .../index.html | 16 ++++ 10--Hold_Shift_and_Check_Checkboxes/style.css | 49 ++++++++++ index.html | 2 +- 6 files changed, 165 insertions(+), 109 deletions(-) create mode 100644 10--Hold_Shift_and_Check_Checkboxes/index-jds.html create mode 100644 10--Hold_Shift_and_Check_Checkboxes/index.html create mode 100644 10--Hold_Shift_and_Check_Checkboxes/style.css diff --git a/10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html b/10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html index 3ce296cc4b..63c908a6be 100644 --- a/10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html +++ b/10--Hold_Shift_and_Check_Checkboxes/index-FINISHED.html @@ -2,62 +2,10 @@ - Document + Hold Shift and Check Checkboxes + - + +
    +
    + +

    This is an inbox layout.

    +
    +
    + +

    Check one item

    +
    +
    + +

    Hold down your Shift key

    +
    +
    + +

    Check a lower item

    +
    +
    + +

    Everything inbetween should also be set to checked

    +
    +
    + +

    Try do it with out any libraries

    +
    +
    + +

    Just regular JavaScript

    +
    +
    + +

    Good Luck!

    +
    +
    + +

    Don't forget to tweet your result!

    +
    +
    + + + + + + diff --git a/10--Hold_Shift_and_Check_Checkboxes/index.html b/10--Hold_Shift_and_Check_Checkboxes/index.html new file mode 100644 index 0000000000..20f4c12b50 --- /dev/null +++ b/10--Hold_Shift_and_Check_Checkboxes/index.html @@ -0,0 +1,16 @@ + + + + + Hold Shift and Check Checkboxes + + + + + + + diff --git a/10--Hold_Shift_and_Check_Checkboxes/style.css b/10--Hold_Shift_and_Check_Checkboxes/style.css new file mode 100644 index 0000000000..f10fc674bd --- /dev/null +++ b/10--Hold_Shift_and_Check_Checkboxes/style.css @@ -0,0 +1,49 @@ +/* style.css */ +html { + font-family: sans-serif; + background:#ffc600; +} + +.inbox { + max-width:400px; + margin:50px auto; + background:white; + border-radius:5px; + box-shadow:10px 10px 0 rgba(0,0,0,0.1); +} + +.item { + display:flex; + align-items:center; + border-bottom: 1px solid #F1F1F1; +} + +.item:last-child { + border-bottom:0; +} + +input:checked + p { + background:#F9F9F9; + text-decoration: line-through; +} + +input[type="checkbox"] { + margin:20px; +} + +p { + margin:0; + padding:20px; + transition:background 0.2s; + flex:1; + font-family:'helvetica neue'; + font-size: 20px; + font-weight: 200; + border-left: 1px solid #D1E2FF; +} + +.details { + text-align: center; + font-size: 15px; +} + diff --git a/index.html b/index.html index 137994032b..5f18110275 100755 --- a/index.html +++ b/index.html @@ -16,7 +16,7 @@
  • 07 - Array Cardio Day 2
  • 08 - Fun with HTML5 Canvas
  • 09 - Dev Tools Domination
  • - +
  • 10 - Hold Shift and Check Checkboxes
  • From 463d149425ac40f142dae46b47a04b6659202c9b Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 29 Dec 2016 14:01:05 -0600 Subject: [PATCH 031/119] finish proj 10. --- 04--Array_Cardio_Day_1/index-jds.html | 1 - .../index-jds.html | 131 +++++++++--------- 2 files changed, 64 insertions(+), 68 deletions(-) diff --git a/04--Array_Cardio_Day_1/index-jds.html b/04--Array_Cardio_Day_1/index-jds.html index 18629d2439..66db281f01 100644 --- a/04--Array_Cardio_Day_1/index-jds.html +++ b/04--Array_Cardio_Day_1/index-jds.html @@ -141,7 +141,6 @@ console.log(deStreets); console.groupEnd(); - // 7. sort Exercise // Sort the people alphabetically by last name const pplSorted = people.sort((a,b) => { diff --git a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html index 078571d657..e80c107fb5 100644 --- a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html +++ b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html @@ -1,95 +1,92 @@ - - Hold Shift and Check Checkboxes - - - -
    -
    - -

    This is an inbox layout.

    -
    -
    - -

    Check one item

    -
    -
    - -

    Hold down your Shift key

    -
    -
    - -

    Check a lower item

    -
    -
    - -

    Everything inbetween should also be set to checked

    -
    -
    - -

    Try do it with out any libraries

    -
    -
    - -

    Just regular JavaScript

    -
    -
    - -

    Good Luck!

    -
    -
    - -

    Don't forget to tweet your result!

    -
    + When a user clicks a checkbox, holds Shift, and then clicks another checkbox a few rows down, all the checkboxes inbetween those two checkboxes should be checked. +--> +
    +
    + +

    This is an inbox layout.

    - +
    + +

    Check one item

    +
    +
    + +

    Hold down your Shift key

    +
    +
    + +

    Check a lower item

    +
    +
    + +

    Everything inbetween should also be set to checked

    +
    +
    + +

    Try do it with out any libraries

    +
    +
    + +

    Just regular JavaScript

    +
    +
    + +

    Good Luck!

    +
    +
    + +

    Don't forget to tweet your result!

    +
    +
    - - From d3541c8c614dfff12ee34a7e6ebe4d2780f9269f Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 29 Dec 2016 14:04:18 -0600 Subject: [PATCH 032/119] clean up project 10. --- 10--Hold_Shift_and_Check_Checkboxes/index-jds.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html index e80c107fb5..67914bd0e9 100644 --- a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html +++ b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html @@ -50,16 +50,15 @@
    From f154070da39b539d894acadd95e6794471c8bd00 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 30 Dec 2016 14:07:29 -0600 Subject: [PATCH 033/119] in the middle of project 11. --- .../index-jds.html | 4 +- 11--Custom_Video_Player/index-FINISHED.html | 27 ++++++ 11--Custom_Video_Player/index-jds.html | 38 ++++++++ 11--Custom_Video_Player/index.html | 21 +--- 11--Custom_Video_Player/scripts-jds.js | 72 ++++++++++++++ 11--Custom_Video_Player/scripts.js | 0 11--Custom_Video_Player/style.css | 96 +++++++++++++------ index.html | 2 +- 8 files changed, 210 insertions(+), 50 deletions(-) create mode 100644 11--Custom_Video_Player/index-FINISHED.html create mode 100644 11--Custom_Video_Player/index-jds.html create mode 100644 11--Custom_Video_Player/scripts-jds.js delete mode 100644 11--Custom_Video_Player/scripts.js diff --git a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html index 67914bd0e9..44a22ce83d 100644 --- a/10--Hold_Shift_and_Check_Checkboxes/index-jds.html +++ b/10--Hold_Shift_and_Check_Checkboxes/index-jds.html @@ -58,7 +58,7 @@ function clickBox(e){ console.group('START clickBox'); - console.log(e.target.checked); + console.log('e.target.checked: ',e.target.checked); // console.log("SHIFT key pressed: " + e.shiftKey); const index = Array.from(checkboxes).indexOf(e.target); // console.log('index: ',index); @@ -71,7 +71,7 @@ } else { sliced = Array.from(checkboxes).slice(lastChecked,index+1); } - console.log('sliced: ',sliced); + console.log('check these ones: ',sliced); if (e.target.checked) { sliced.forEach(slice => slice.checked = true); } else { diff --git a/11--Custom_Video_Player/index-FINISHED.html b/11--Custom_Video_Player/index-FINISHED.html new file mode 100644 index 0000000000..dee25cd7d0 --- /dev/null +++ b/11--Custom_Video_Player/index-FINISHED.html @@ -0,0 +1,27 @@ + + + + + HTML Video Player + + + + +
    + + +
    +
    +
    +
    + + + + + +
    +
    + + + + diff --git a/11--Custom_Video_Player/index-jds.html b/11--Custom_Video_Player/index-jds.html new file mode 100644 index 0000000000..84ecb9f7bb --- /dev/null +++ b/11--Custom_Video_Player/index-jds.html @@ -0,0 +1,38 @@ + + + + + + HTML Video Player + + + + + + +
    + + + + +
    +
    +
    +
    + + + + + +
    + +
    + + + + + diff --git a/11--Custom_Video_Player/index.html b/11--Custom_Video_Player/index.html index fe2b55b394..f3e3d6d8dc 100644 --- a/11--Custom_Video_Player/index.html +++ b/11--Custom_Video_Player/index.html @@ -3,25 +3,14 @@ HTML Video Player - -
    - + -
    -
    -
    -
    - - - - - -
    -
    - - diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js new file mode 100644 index 0000000000..cf0bad14be --- /dev/null +++ b/11--Custom_Video_Player/scripts-jds.js @@ -0,0 +1,72 @@ +/* get elements */ +const player = document.querySelector('.player'); +// console.log('player: ', player); + +const video = player.querySelector('.viewer'); +// console.log('video: ', video); + +const controls = player.querySelector('.player__controls'); +// console.log('controls: ', controls); + +const progress = controls.querySelector('.progress'); +// console.log(progress); +const progressBar = controls.querySelector('.progress__filled'); +// console.log(progressBar); + +const toggle = controls.querySelector('.toggle'); +console.log(toggle); +const skipButtons = controls.querySelectorAll('[data-skip]'); +// console.log(skipButtons); +const ranges = controls.querySelector('[type="range"]'); +// console.log(ranges); + +/* create functions */ +function togglePlayer (e) { + console.group('START togglePlayer'); + // console.log('e.target: ',e.target); + // console.log('this: ',this); + + // Stop propagation. + e = e || window.event // cross-browser event + if (e.stopPropagation) { + // W3C standard variant + e.stopPropagation() + } else { + // IE variant + e.cancelBubble = true + } + + + // if (video.paused) { + // video.play(); + // } else { + // video.pause(); + // } + // or + const method = video.paused ? 'play':'pause'; + video[method](); + console.groupEnd(); +} + +function toggleButton() { +/* +play triangle +▸ +▸ +▸ +▸ + +*pause marker (use 2) +▮ +▮ +▮ +*/ + video.paused ? toggle.innerHTML='►' : toggle.innerHTML='▮▮'; +} + +/* hook up event listeners */ + +video.addEventListener('click',togglePlayer); +video.addEventListener('play',toggleButton); +video.addEventListener('pause',toggleButton); +toggle.addEventListener('click',togglePlayer); \ No newline at end of file diff --git a/11--Custom_Video_Player/scripts.js b/11--Custom_Video_Player/scripts.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/11--Custom_Video_Player/style.css b/11--Custom_Video_Player/style.css index c07581c1c0..a818df50de 100644 --- a/11--Custom_Video_Player/style.css +++ b/11--Custom_Video_Player/style.css @@ -1,17 +1,17 @@ -html { +*, *:before, *:after { box-sizing: border-box; + padding: 0; + margin: 0; + /* background-color: #f00; */ } -*, *:before, *:after { - box-sizing: inherit; -} +html {} body { - padding: 0; display:flex; background:#7A419B; min-height:100vh; - background: linear-gradient(135deg, #7c1599 0%,#921099 48%,#7e4ae8 100%); + background: linear-gradient(135deg, #7c1599 0%,#921099 50%,#7e4ae8 100%); background-size:cover; align-items: center; justify-content: center; @@ -19,26 +19,32 @@ body { .player { max-width:750px; - border:5px solid rgba(0,0,0,0.2); - box-shadow:0 0 20px rgba(0,0,0,0.2); + /* border:5px solid rgba(0,0,0,0.2); */ + box-shadow: + 0 0 0.5rem 0 rgba(0,0,0,0.25), + 0 1rem 2rem 0 rgba(0,0,0,0.25); position: relative; font-size: 0; overflow: hidden; } +video {} + .player__video { width: 100%; } .player__button { + color:white; background:none; border:0; + font-size:14px; line-height:1; - color:white; text-align: center; outline:0; padding: 0; cursor:pointer; + min-width:44px; max-width:50px; } @@ -59,7 +65,7 @@ body { transform: translateY(100%) translateY(-5px); transition:all .3s; flex-wrap:wrap; - background:rgba(0,0,0,0.1); + background:rgba(0,0,0,0.5); } .player:hover .player__controls { @@ -67,7 +73,7 @@ body { } .player:hover .progress { - height:15px; + height:0.75rem; } .player__controls > * { @@ -79,7 +85,7 @@ body { position: relative; display:flex; flex-basis:100%; - height:5px; + height:0.5rem; transition:height 0.3s; background:rgba(0,0,0,0.5); cursor:ew-resize; @@ -92,54 +98,82 @@ body { flex-basis:50%; } +input, button {position:relative;} + /* unholy css to style input type="range" */ input[type=range] { -webkit-appearance: none; background:transparent; width: 100%; - margin: 0 5px; + padding:5px 10px; } + input[type=range]:focus { outline: none; } + input[type=range]::-webkit-slider-runnable-track { width: 100%; - height: 8.4px; + height: 0.25rem; cursor: pointer; - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); + box-shadow: + 1px 1px 1px rgba(0, 0, 0, 0), + 0 0 1px rgba(13, 13, 13, 0); background: rgba(255,255,255,0.8); - border-radius: 1.3px; - border: 0.2px solid rgba(1, 1, 1, 0); + border-radius: 5px; + /* border: 2px solid rgba(1, 1, 1, 0); */ } + input[type=range]::-webkit-slider-thumb { - box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); - height: 15px; - width: 15px; - border-radius: 50px; + height: 1rem; + width: 1rem; + border-radius: 100%; background: #ffc600; cursor: pointer; -webkit-appearance: none; - margin-top: -3.5px; - box-shadow:0 0 2px rgba(0,0,0,0.2); + margin-top: -0.333333333rem; + box-shadow: + 0 0 0.25rem 0 rgba(0,0,0,0.5), + 0 0.25rem 0.5rem 0 rgba(0,0,0,0.25); } + input[type=range]:focus::-wefbkit-slider-runnable-track { background: #bada55; } -input[type=range]::-moz-range-track { + +/* input[type=range]::-moz-range-track { width: 100%; height: 8.4px; cursor: pointer; - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); + box-shadow: + 1px 1px 1px rgba(0, 0, 0, 0), + 0 0 1px rgba(13, 13, 13, 0); background: #ffffff; border-radius: 1.3px; border: 0.2px solid rgba(1, 1, 1, 0); -} -input[type=range]::-moz-range-thumb { - box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); - height: 15px; - width: 15px; +} */ + +/* input[type=range]::-moz-range-thumb { + box-shadow: + 0 0 0 rgba(0, 0, 0, 0), + 0 0 0 rgba(13, 13, 13, 0); + height: 1rem; + width: 1rem; border-radius: 50px; background: #ffc600; cursor: pointer; -} +} */ + +.toggle {background-color:rgba(255,0,0,0.5);} +button[name='skipBack'] {background-color:rgba(0,255,0,0.5);} +button[name='skipAhead'] {background-color:rgba(0,0,255,0.5);} +input[name='volume'] {background-color:rgba(255,0,255,0.5);} +input[name='playbackRate'] {background-color:rgba(255,255,0,0.5);} + +*:before {position: absolute; background-color: #000; z-index: 0;} +/* .toggle:before {content:"play/pause";} */ +/* button[name='skipBack']:before {content:"skip back";} */ +/* button[name='skipAhead']:before {content:"skip ahead";} */ +/* input[name='volume']:before {content:"volume";} */ +/* input[name='playbackRate']:before {content:"playbackRate";} */ diff --git a/index.html b/index.html index 5f18110275..7c16e2409d 100755 --- a/index.html +++ b/index.html @@ -17,7 +17,7 @@
  • 08 - Fun with HTML5 Canvas
  • 09 - Dev Tools Domination
  • 10 - Hold Shift and Check Checkboxes
  • - +
  • 11 - Custom Video Player
  • From 9cfb947341d4642ba2966a61ad8ed5b27a4a3ff8 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 10:53:32 -0600 Subject: [PATCH 034/119] solve skip fun on my own. --- 11--Custom_Video_Player/scripts-jds.js | 27 ++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index cf0bad14be..c75bfc4ec8 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -1,4 +1,6 @@ -/* get elements */ +/** + * get elements + */ const player = document.querySelector('.player'); // console.log('player: ', player); @@ -20,13 +22,15 @@ const skipButtons = controls.querySelectorAll('[data-skip]'); const ranges = controls.querySelector('[type="range"]'); // console.log(ranges); -/* create functions */ +/** + * create functions + */ function togglePlayer (e) { console.group('START togglePlayer'); // console.log('e.target: ',e.target); // console.log('this: ',this); - // Stop propagation. + /* Stop propagation */ e = e || window.event // cross-browser event if (e.stopPropagation) { // W3C standard variant @@ -42,7 +46,7 @@ function togglePlayer (e) { // } else { // video.pause(); // } - // or + /* or */ const method = video.paused ? 'play':'pause'; video[method](); console.groupEnd(); @@ -64,9 +68,20 @@ play triangle video.paused ? toggle.innerHTML='►' : toggle.innerHTML='▮▮'; } -/* hook up event listeners */ +function skip() { + console.log('SKIPPING!!',this.dataset.skip); + const skipVal = parseInt(this.dataset.skip); + // console.log('currentTime: ',video.currentTime); + if (video.played) { + video.currentTime = video.currentTime + (skipVal); + } +} +/** + * hook up event listeners + */ video.addEventListener('click',togglePlayer); video.addEventListener('play',toggleButton); video.addEventListener('pause',toggleButton); -toggle.addEventListener('click',togglePlayer); \ No newline at end of file +toggle.addEventListener('click',togglePlayer); +skipButtons.forEach(button => button.addEventListener('click',skip)); From ff63e50afd22e7a068f56a923822a204acb8c0f5 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 10:56:40 -0600 Subject: [PATCH 035/119] optimize skip fun. --- 11--Custom_Video_Player/scripts-jds.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index c75bfc4ec8..f71d2d9c3d 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -70,11 +70,12 @@ play triangle function skip() { console.log('SKIPPING!!',this.dataset.skip); - const skipVal = parseInt(this.dataset.skip); - // console.log('currentTime: ',video.currentTime); + const skipVal = parseFloat(this.dataset.skip); + console.log('old currentTime: ',video.currentTime); if (video.played) { - video.currentTime = video.currentTime + (skipVal); + video.currentTime += (skipVal); } + console.log('new currentTime: ',video.currentTime); } /** From 09ba5b50d904c4873929259e56a6f6d8132d9fb4 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 11:41:45 -0600 Subject: [PATCH 036/119] handle range slider changes. --- 11--Custom_Video_Player/scripts-jds.js | 10 +++++++++- 11--Custom_Video_Player/style.css | 6 +++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index f71d2d9c3d..d7b2c95412 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -19,7 +19,7 @@ const toggle = controls.querySelector('.toggle'); console.log(toggle); const skipButtons = controls.querySelectorAll('[data-skip]'); // console.log(skipButtons); -const ranges = controls.querySelector('[type="range"]'); +const ranges = controls.querySelectorAll('[type="range"]'); // console.log(ranges); /** @@ -78,6 +78,13 @@ function skip() { console.log('new currentTime: ',video.currentTime); } +function updateRange() { + console.log('updateRange: ', this.name,'value: '+this.value); + console.log('old video['+this.name+'] =', video[this.name]); + video[this.name] = this.value; + console.log('new video['+this.name+'] =', video[this.name]); +} + /** * hook up event listeners */ @@ -86,3 +93,4 @@ video.addEventListener('play',toggleButton); video.addEventListener('pause',toggleButton); toggle.addEventListener('click',togglePlayer); skipButtons.forEach(button => button.addEventListener('click',skip)); +ranges.forEach(range => range.addEventListener('change',updateRange)); diff --git a/11--Custom_Video_Player/style.css b/11--Custom_Video_Player/style.css index a818df50de..bed7556d74 100644 --- a/11--Custom_Video_Player/style.css +++ b/11--Custom_Video_Player/style.css @@ -171,9 +171,9 @@ button[name='skipAhead'] {background-color:rgba(0,0,255,0.5);} input[name='volume'] {background-color:rgba(255,0,255,0.5);} input[name='playbackRate'] {background-color:rgba(255,255,0,0.5);} -*:before {position: absolute; background-color: #000; z-index: 0;} +*:before {position: absolute; color:white; background-color:rgba(0,0,0,0); z-index:0; font-size:1rem; text-shadow:0 0.25rem 0.5rem black;} /* .toggle:before {content:"play/pause";} */ /* button[name='skipBack']:before {content:"skip back";} */ /* button[name='skipAhead']:before {content:"skip ahead";} */ -/* input[name='volume']:before {content:"volume";} */ -/* input[name='playbackRate']:before {content:"playbackRate";} */ +input[name='volume']:before {content:"volume";} +input[name='playbackRate']:before {content:"speed";} From 6d898c6d40e12de26b149ea513a5a3dd1e10657c Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 14:35:17 -0600 Subject: [PATCH 037/119] handle progress bar auto-update (while playing). --- 11--Custom_Video_Player/index-jds.html | 2 + 11--Custom_Video_Player/scripts-jds.js | 47 +++++++++- 11--Custom_Video_Player/style.css | 118 +++++++++++++------------ 3 files changed, 108 insertions(+), 59 deletions(-) diff --git a/11--Custom_Video_Player/index-jds.html b/11--Custom_Video_Player/index-jds.html index 84ecb9f7bb..414069e480 100644 --- a/11--Custom_Video_Player/index-jds.html +++ b/11--Custom_Video_Player/index-jds.html @@ -4,7 +4,9 @@ HTML Video Player + + diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index d7b2c95412..7ce7bbdb0b 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -26,7 +26,7 @@ const ranges = controls.querySelectorAll('[type="range"]'); * create functions */ function togglePlayer (e) { - console.group('START togglePlayer'); + // console.group('START togglePlayer'); // console.log('e.target: ',e.target); // console.log('this: ',this); @@ -40,7 +40,6 @@ function togglePlayer (e) { e.cancelBubble = true } - // if (video.paused) { // video.play(); // } else { @@ -49,9 +48,10 @@ function togglePlayer (e) { /* or */ const method = video.paused ? 'play':'pause'; video[method](); - console.groupEnd(); + // console.groupEnd(); } +// change icon of button when toggling play/pause. function toggleButton() { /* play triangle @@ -85,6 +85,42 @@ function updateRange() { console.log('new video['+this.name+'] =', video[this.name]); } +function autoProgress() { + if (!isSkipping) { + // console.group('START autoProgress'); + // console.log('autoProgress -- video.duration', video.duration); + console.log('autoProgress -- old progressBar: ', progressBar.style.flexBasis); + progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; + console.log('autoProgress -- new progressBar: ', progressBar.style.flexBasis); + // console.groupEnd(); + } +} + +window.setInterval(autoProgress, 100); + +let isSkipping = false; + +/*function manualProgress(e) { + if (isSkipping) { + // console.group('START manualProgress: ', isSkipping); + // console.log('manualProgress -- e.type: ', e.type); + console.log('manualProgress -- e.target: ', e.target); + console.log('manualProgress -- progressBar: ', progressBar); + // console.log('manualProgress -- e.target.style.flexBasis: ', e.target.style.flexBasis); + // console.log('manualProgress -- e.target.offsetWidth: ', e.target.offsetWidth); + // console.log('manualProgress -- e.offsetX: ', e.offsetX); + // console.log('manualProgress -- old manualProgress: ', progressBar.style.flexBasis); + console.log('manualProgress -- old video.currentTime: ',video.currentTime); + video.currentTime = video.duration * (e.offsetX / e.target.offsetWidth); + // progressBar.style.flexBasis = (e.offsetX / e.target.offsetWidth)*100+'%'; + console.log('manualProgress -- new video.currentTime: ',video.currentTime); + // console.log('manualProgress -- progressBar.style.flexBasis: ',progressBar.style.flexBasis); + // autoProgress; + // console.log('manualProgress -- new manualProgress: ', progressBar.style.flexBasis); + // console.groupEnd(); + } +}*/ + /** * hook up event listeners */ @@ -94,3 +130,8 @@ video.addEventListener('pause',toggleButton); toggle.addEventListener('click',togglePlayer); skipButtons.forEach(button => button.addEventListener('click',skip)); ranges.forEach(range => range.addEventListener('change',updateRange)); + +// progress.addEventListener('mousedown', () => isSkipping = true); +// progress.addEventListener('mousemove',manualProgress); +// progress.addEventListener('mouseup', () => isSkipping = false); +// progress.addEventListener('mouseout', () => isSkipping = false); diff --git a/11--Custom_Video_Player/style.css b/11--Custom_Video_Player/style.css index bed7556d74..b3ebee0e3c 100644 --- a/11--Custom_Video_Player/style.css +++ b/11--Custom_Video_Player/style.css @@ -1,8 +1,8 @@ *, *:before, *:after { - box-sizing: border-box; - padding: 0; - margin: 0; - /* background-color: #f00; */ + box-sizing:border-box; + padding:0; + margin:0; + /* background-color:#f00; */ } html {} @@ -11,10 +11,10 @@ body { display:flex; background:#7A419B; min-height:100vh; - background: linear-gradient(135deg, #7c1599 0%,#921099 50%,#7e4ae8 100%); + background:linear-gradient(135deg, #7c1599 0%,#921099 50%,#7e4ae8 100%); background-size:cover; - align-items: center; - justify-content: center; + align-items:center; + justify-content:center; } .player { @@ -23,15 +23,13 @@ body { box-shadow: 0 0 0.5rem 0 rgba(0,0,0,0.25), 0 1rem 2rem 0 rgba(0,0,0,0.25); - position: relative; - font-size: 0; - overflow: hidden; + position:relative; + font-size:0; + overflow:hidden; } -video {} - .player__video { - width: 100%; + width:100%; } .player__button { @@ -40,16 +38,16 @@ video {} border:0; font-size:14px; line-height:1; - text-align: center; + text-align:center; outline:0; - padding: 0; + padding:0; cursor:pointer; min-width:44px; max-width:50px; } .player__button:focus { - border-color: #ffc600; + border-color:#ffc600; } .player__slider { @@ -59,17 +57,17 @@ video {} .player__controls { display:flex; - position: absolute; + position:absolute; bottom:0; - width: 100%; - transform: translateY(100%) translateY(-5px); + width:100%; + transform:translateY(100%) translateY(-5px); transition:all .3s; flex-wrap:wrap; background:rgba(0,0,0,0.5); } .player:hover .player__controls { - transform: translateY(0); + transform:translateY(0); } .player:hover .progress { @@ -82,7 +80,7 @@ video {} .progress { flex:10; - position: relative; + position:relative; display:flex; flex-basis:100%; height:0.5rem; @@ -94,8 +92,8 @@ video {} .progress__filled { width:50%; background:#ffc600; - flex:0; - flex-basis:50%; + flex:0; + flex-basis:50%; } input, button {position:relative;} @@ -103,66 +101,66 @@ input, button {position:relative;} /* unholy css to style input type="range" */ input[type=range] { - -webkit-appearance: none; + -webkit-appearance:none; background:transparent; - width: 100%; + width:100%; padding:5px 10px; } input[type=range]:focus { - outline: none; + outline:none; } input[type=range]::-webkit-slider-runnable-track { - width: 100%; - height: 0.25rem; - cursor: pointer; - box-shadow: + width:100%; + height:0.25rem; + cursor:pointer; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); - background: rgba(255,255,255,0.8); - border-radius: 5px; - /* border: 2px solid rgba(1, 1, 1, 0); */ + background:rgba(255,255,255,0.8); + border-radius:5px; + /* border:2px solid rgba(1, 1, 1, 0); */ } input[type=range]::-webkit-slider-thumb { - height: 1rem; - width: 1rem; - border-radius: 100%; - background: #ffc600; - cursor: pointer; - -webkit-appearance: none; - margin-top: -0.333333333rem; - box-shadow: + height:1rem; + width:1rem; + border-radius:100%; + background:#ffc600; + cursor:pointer; + -webkit-appearance:none; + margin-top:-0.333333333rem; + box-shadow: 0 0 0.25rem 0 rgba(0,0,0,0.5), 0 0.25rem 0.5rem 0 rgba(0,0,0,0.25); } input[type=range]:focus::-wefbkit-slider-runnable-track { - background: #bada55; + background:#bada55; } /* input[type=range]::-moz-range-track { - width: 100%; - height: 8.4px; - cursor: pointer; - box-shadow: + width:100%; + height:8.4px; + cursor:pointer; + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0), 0 0 1px rgba(13, 13, 13, 0); - background: #ffffff; - border-radius: 1.3px; - border: 0.2px solid rgba(1, 1, 1, 0); + background:#ffffff; + border-radius:1.3px; + border:0.2px solid rgba(1, 1, 1, 0); } */ /* input[type=range]::-moz-range-thumb { - box-shadow: + box-shadow: 0 0 0 rgba(0, 0, 0, 0), 0 0 0 rgba(13, 13, 13, 0); - height: 1rem; - width: 1rem; - border-radius: 50px; - background: #ffc600; - cursor: pointer; + height:1rem; + width:1rem; + border-radius:50px; + background:#ffc600; + cursor:pointer; } */ .toggle {background-color:rgba(255,0,0,0.5);} @@ -171,7 +169,15 @@ button[name='skipAhead'] {background-color:rgba(0,0,255,0.5);} input[name='volume'] {background-color:rgba(255,0,255,0.5);} input[name='playbackRate'] {background-color:rgba(255,255,0,0.5);} -*:before {position: absolute; color:white; background-color:rgba(0,0,0,0); z-index:0; font-size:1rem; text-shadow:0 0.25rem 0.5rem black;} +*:before { + position:absolute; + color:white; + background-color:rgba(0,0,0,0); + z-index:0; + font-size:1rem; + text-shadow:0 0.25rem 0.25rem rgba(0,0,0,0.5); +} + /* .toggle:before {content:"play/pause";} */ /* button[name='skipBack']:before {content:"skip back";} */ /* button[name='skipAhead']:before {content:"skip ahead";} */ From 7f2fe1745d6824f4a25f93cd84a5aa87bf2c984a Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 15:32:21 -0600 Subject: [PATCH 038/119] make scrubbing work...mostly. --- 11--Custom_Video_Player/index-jds.html | 7 +++ 11--Custom_Video_Player/scripts-jds.js | 67 ++++++++++++++++---------- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/11--Custom_Video_Player/index-jds.html b/11--Custom_Video_Player/index-jds.html index 414069e480..a4feea5055 100644 --- a/11--Custom_Video_Player/index-jds.html +++ b/11--Custom_Video_Player/index-jds.html @@ -22,14 +22,21 @@ src="https://player.vimeo.com/external/194837908.sd.mp4?s=c350076905b78c67f74d7ee39fdb4fef01d12420&profile_id=164">
    +
    + + + + + +
    diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index 7ce7bbdb0b..d437776dd7 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -16,7 +16,7 @@ const progressBar = controls.querySelector('.progress__filled'); // console.log(progressBar); const toggle = controls.querySelector('.toggle'); -console.log(toggle); +// console.log(toggle); const skipButtons = controls.querySelectorAll('[data-skip]'); // console.log(skipButtons); const ranges = controls.querySelectorAll('[type="range"]'); @@ -69,30 +69,31 @@ play triangle } function skip() { - console.log('SKIPPING!!',this.dataset.skip); + // console.log('SKIPPING!!',this.dataset.skip); const skipVal = parseFloat(this.dataset.skip); - console.log('old currentTime: ',video.currentTime); + // console.log('old currentTime: ',video.currentTime); if (video.played) { video.currentTime += (skipVal); } - console.log('new currentTime: ',video.currentTime); + // console.log('new currentTime: ',video.currentTime); } function updateRange() { - console.log('updateRange: ', this.name,'value: '+this.value); - console.log('old video['+this.name+'] =', video[this.name]); + // console.log(this); + // console.log('updateRange: ', this.name,'value: '+this.value); + // console.log('old video['+this.name+'] =', video[this.name]); video[this.name] = this.value; - console.log('new video['+this.name+'] =', video[this.name]); + // console.log('new video['+this.name+'] =', video[this.name]); } function autoProgress() { if (!isSkipping) { - // console.group('START autoProgress'); + console.group('START autoProgress'); // console.log('autoProgress -- video.duration', video.duration); console.log('autoProgress -- old progressBar: ', progressBar.style.flexBasis); progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; console.log('autoProgress -- new progressBar: ', progressBar.style.flexBasis); - // console.groupEnd(); + console.groupEnd(); } } @@ -100,26 +101,39 @@ window.setInterval(autoProgress, 100); let isSkipping = false; -/*function manualProgress(e) { +function manualProgress(e) { + + /* Stop propagation */ + e = e || window.event // cross-browser event + if (e.stopPropagation) { + // W3C standard variant + e.stopPropagation() + } else { + // IE variant + e.cancelBubble = true + } + + console.group('START manualProgress: ', isSkipping); + console.log('manualProgress -- e.target: ', e.target.classList[0]); + console.log('manualProgress -- e.offsetX: ', e.offsetX); + console.log('manualProgress -- progress.offsetWidth: ', progress.offsetWidth); + console.log('manualProgress -- position: ', (e.offsetX / progress.offsetWidth)*100+'%'); if (isSkipping) { - // console.group('START manualProgress: ', isSkipping); // console.log('manualProgress -- e.type: ', e.type); - console.log('manualProgress -- e.target: ', e.target); - console.log('manualProgress -- progressBar: ', progressBar); + // console.log('manualProgress -- e.target: ', e.target.classList[0]); + // console.log('manualProgress -- progressBar: ', progressBar.classList[0]); // console.log('manualProgress -- e.target.style.flexBasis: ', e.target.style.flexBasis); - // console.log('manualProgress -- e.target.offsetWidth: ', e.target.offsetWidth); - // console.log('manualProgress -- e.offsetX: ', e.offsetX); // console.log('manualProgress -- old manualProgress: ', progressBar.style.flexBasis); - console.log('manualProgress -- old video.currentTime: ',video.currentTime); - video.currentTime = video.duration * (e.offsetX / e.target.offsetWidth); - // progressBar.style.flexBasis = (e.offsetX / e.target.offsetWidth)*100+'%'; - console.log('manualProgress -- new video.currentTime: ',video.currentTime); + // console.log('manualProgress -- old video.currentTime: ',video.currentTime); + video.currentTime = video.duration * (e.offsetX / progress.offsetWidth); + progressBar.style.flexBasis = (e.offsetX / progress.offsetWidth)*100+'%'; + // console.log('manualProgress -- new video.currentTime: ',video.currentTime); // console.log('manualProgress -- progressBar.style.flexBasis: ',progressBar.style.flexBasis); // autoProgress; // console.log('manualProgress -- new manualProgress: ', progressBar.style.flexBasis); - // console.groupEnd(); } -}*/ + console.groupEnd(); +} /** * hook up event listeners @@ -131,7 +145,10 @@ toggle.addEventListener('click',togglePlayer); skipButtons.forEach(button => button.addEventListener('click',skip)); ranges.forEach(range => range.addEventListener('change',updateRange)); -// progress.addEventListener('mousedown', () => isSkipping = true); -// progress.addEventListener('mousemove',manualProgress); -// progress.addEventListener('mouseup', () => isSkipping = false); -// progress.addEventListener('mouseout', () => isSkipping = false); +progress.addEventListener('mousedown', () => { + isSkipping = true; + manualProgress(); +}); +progress.addEventListener('mousemove', manualProgress); +progress.addEventListener('mouseup', () => isSkipping = false); +progress.addEventListener('mouseout', () => isSkipping = false); From db3e2785f717f5527983089ba9b9d2dfeccdab2c Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 15:40:49 -0600 Subject: [PATCH 039/119] optimize. "mouseout" was preventing bi-directional scrubbing wishing same mouse interval. --- 11--Custom_Video_Player/scripts-jds.js | 43 +++++++++----------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index d437776dd7..c58196591f 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -87,19 +87,18 @@ function updateRange() { } function autoProgress() { - if (!isSkipping) { - console.group('START autoProgress'); - // console.log('autoProgress -- video.duration', video.duration); - console.log('autoProgress -- old progressBar: ', progressBar.style.flexBasis); + if (!isScrubbing) { + console.group('START autoProgress -- isScrubbing: ', isScrubbing); + console.log('autoProgress -- old currentTime: ', video.currentTime); progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; - console.log('autoProgress -- new progressBar: ', progressBar.style.flexBasis); + console.log('autoProgress -- new currentTime: ', video.currentTime); console.groupEnd(); } } window.setInterval(autoProgress, 100); -let isSkipping = false; +let isScrubbing = false; function manualProgress(e) { @@ -113,26 +112,14 @@ function manualProgress(e) { e.cancelBubble = true } - console.group('START manualProgress: ', isSkipping); - console.log('manualProgress -- e.target: ', e.target.classList[0]); - console.log('manualProgress -- e.offsetX: ', e.offsetX); - console.log('manualProgress -- progress.offsetWidth: ', progress.offsetWidth); - console.log('manualProgress -- position: ', (e.offsetX / progress.offsetWidth)*100+'%'); - if (isSkipping) { - // console.log('manualProgress -- e.type: ', e.type); - // console.log('manualProgress -- e.target: ', e.target.classList[0]); - // console.log('manualProgress -- progressBar: ', progressBar.classList[0]); - // console.log('manualProgress -- e.target.style.flexBasis: ', e.target.style.flexBasis); - // console.log('manualProgress -- old manualProgress: ', progressBar.style.flexBasis); - // console.log('manualProgress -- old video.currentTime: ',video.currentTime); + if (isScrubbing) { + console.group('START manualProgress -- isScrubbing: ', isScrubbing); + console.log('manualProgress -- old currentTime: ',video.currentTime); video.currentTime = video.duration * (e.offsetX / progress.offsetWidth); - progressBar.style.flexBasis = (e.offsetX / progress.offsetWidth)*100+'%'; - // console.log('manualProgress -- new video.currentTime: ',video.currentTime); - // console.log('manualProgress -- progressBar.style.flexBasis: ',progressBar.style.flexBasis); - // autoProgress; - // console.log('manualProgress -- new manualProgress: ', progressBar.style.flexBasis); - } + progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; + console.log('manualProgress -- new currentTime: ',video.currentTime); console.groupEnd(); + } } /** @@ -146,9 +133,9 @@ skipButtons.forEach(button => button.addEventListener('click',skip)); ranges.forEach(range => range.addEventListener('change',updateRange)); progress.addEventListener('mousedown', () => { - isSkipping = true; - manualProgress(); + isScrubbing = true; + // manualProgress(); }); progress.addEventListener('mousemove', manualProgress); -progress.addEventListener('mouseup', () => isSkipping = false); -progress.addEventListener('mouseout', () => isSkipping = false); +progress.addEventListener('mouseup', () => isScrubbing = false); +// progress.addEventListener('mouseout', () => isScrubbing = false); From e9c86685884b22343acb2cce68d8ad482aae505f Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 3 Jan 2017 16:28:04 -0600 Subject: [PATCH 040/119] optimize & attempt fullscreen button. --- 11--Custom_Video_Player/index-jds.html | 2 ++ 11--Custom_Video_Player/scripts-jds.js | 45 +++++++++++++++++--------- 11--Custom_Video_Player/style.css | 18 ++++++----- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/11--Custom_Video_Player/index-jds.html b/11--Custom_Video_Player/index-jds.html index a4feea5055..5838a5e467 100644 --- a/11--Custom_Video_Player/index-jds.html +++ b/11--Custom_Video_Player/index-jds.html @@ -37,6 +37,8 @@ + + diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index c58196591f..29688be2bf 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -22,6 +22,8 @@ const skipButtons = controls.querySelectorAll('[data-skip]'); const ranges = controls.querySelectorAll('[type="range"]'); // console.log(ranges); +const fullScreen = controls.querySelector('[name="fullScreen"]'); + /** * create functions */ @@ -90,18 +92,18 @@ function autoProgress() { if (!isScrubbing) { console.group('START autoProgress -- isScrubbing: ', isScrubbing); console.log('autoProgress -- old currentTime: ', video.currentTime); - progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; + // progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; + const percent = (video.currentTime / video.duration)*100; + // console.log(percent); + progressBar.style.flexBasis = `${percent}%`; console.log('autoProgress -- new currentTime: ', video.currentTime); console.groupEnd(); } } -window.setInterval(autoProgress, 100); - let isScrubbing = false; -function manualProgress(e) { - +function scrub(e) { /* Stop propagation */ e = e || window.event // cross-browser event if (e.stopPropagation) { @@ -111,14 +113,19 @@ function manualProgress(e) { // IE variant e.cancelBubble = true } + console.group('START scrub -- isScrubbing: ', isScrubbing); + console.log('scrub -- old currentTime: ',video.currentTime); + video.currentTime = video.duration * (e.offsetX / progress.offsetWidth); + progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; + console.log('scrub -- new currentTime: ',video.currentTime); + console.groupEnd(); +} - if (isScrubbing) { - console.group('START manualProgress -- isScrubbing: ', isScrubbing); - console.log('manualProgress -- old currentTime: ',video.currentTime); - video.currentTime = video.duration * (e.offsetX / progress.offsetWidth); - progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; - console.log('manualProgress -- new currentTime: ',video.currentTime); - console.groupEnd(); +function goFullScreen(e) { + console.log('START goFullScreen'); + if (video.requestFullscreen) { + console.log('requestFullscreen'); + video.requestFullscreen(); } } @@ -128,14 +135,22 @@ function manualProgress(e) { video.addEventListener('click',togglePlayer); video.addEventListener('play',toggleButton); video.addEventListener('pause',toggleButton); +video.addEventListener('timeupdate',autoProgress); + toggle.addEventListener('click',togglePlayer); + skipButtons.forEach(button => button.addEventListener('click',skip)); + +fullScreen.addEventListener('click', () => { + goFullScreen; +}); + ranges.forEach(range => range.addEventListener('change',updateRange)); progress.addEventListener('mousedown', () => { isScrubbing = true; - // manualProgress(); + scrub(); }); -progress.addEventListener('mousemove', manualProgress); +progress.addEventListener('mousemove', (e) => isScrubbing && scrub(e)); progress.addEventListener('mouseup', () => isScrubbing = false); -// progress.addEventListener('mouseout', () => isScrubbing = false); +// progress.addEventListener('mouseout', () => isScrubbing = false); // do not use this event. diff --git a/11--Custom_Video_Player/style.css b/11--Custom_Video_Player/style.css index b3ebee0e3c..0467f0af11 100644 --- a/11--Custom_Video_Player/style.css +++ b/11--Custom_Video_Player/style.css @@ -34,7 +34,7 @@ body { .player__button { color:white; - background:none; + /* background:none; */ border:0; font-size:14px; line-height:1; @@ -66,6 +66,8 @@ body { background:rgba(0,0,0,0.5); } +.player__controls > * {background-color:rgba(0,0,0,0.25);} + .player:hover .player__controls { transform:translateY(0); } @@ -83,7 +85,7 @@ body { position:relative; display:flex; flex-basis:100%; - height:0.5rem; + height:1rem; transition:height 0.3s; background:rgba(0,0,0,0.5); cursor:ew-resize; @@ -102,7 +104,7 @@ input, button {position:relative;} input[type=range] { -webkit-appearance:none; - background:transparent; + /* background:transparent; */ width:100%; padding:5px 10px; } @@ -163,11 +165,11 @@ input[type=range]:focus::-wefbkit-slider-runnable-track { cursor:pointer; } */ -.toggle {background-color:rgba(255,0,0,0.5);} -button[name='skipBack'] {background-color:rgba(0,255,0,0.5);} -button[name='skipAhead'] {background-color:rgba(0,0,255,0.5);} -input[name='volume'] {background-color:rgba(255,0,255,0.5);} -input[name='playbackRate'] {background-color:rgba(255,255,0,0.5);} + /* .toggle {background-color:rgba(255,0,0,0.5);} */ + /* button[name='skipBack'] {background-color:rgba(0,255,0,0.5);} */ + /* button[name='skipAhead'] {background-color:rgba(0,0,255,0.5);} */ + /* input[name='volume'] {background-color:rgba(255,0,255,0.5);} */ + /* input[name='playbackRate'] {background-color:rgba(255,255,0,0.5);} */ *:before { position:absolute; From f5ca6529aa64689209c1bae620e4711d3d8fe5b2 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 11:45:09 -0600 Subject: [PATCH 041/119] optimize pros 11 scripts. --- 11--Custom_Video_Player/scripts-jds.js | 37 +++++++++----------------- 11--Custom_Video_Player/style.css | 1 + 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index 29688be2bf..21e53d1547 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -2,26 +2,13 @@ * get elements */ const player = document.querySelector('.player'); -// console.log('player: ', player); - const video = player.querySelector('.viewer'); -// console.log('video: ', video); - const controls = player.querySelector('.player__controls'); -// console.log('controls: ', controls); - const progress = controls.querySelector('.progress'); -// console.log(progress); const progressBar = controls.querySelector('.progress__filled'); -// console.log(progressBar); - const toggle = controls.querySelector('.toggle'); -// console.log(toggle); const skipButtons = controls.querySelectorAll('[data-skip]'); -// console.log(skipButtons); const ranges = controls.querySelectorAll('[type="range"]'); -// console.log(ranges); - const fullScreen = controls.querySelector('[name="fullScreen"]'); /** @@ -88,16 +75,16 @@ function updateRange() { // console.log('new video['+this.name+'] =', video[this.name]); } -function autoProgress() { +function fill() { if (!isScrubbing) { - console.group('START autoProgress -- isScrubbing: ', isScrubbing); - console.log('autoProgress -- old currentTime: ', video.currentTime); + // console.group('START fill -- isScrubbing: ', isScrubbing); + // console.log('fill -- old currentTime: ', video.currentTime); // progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; const percent = (video.currentTime / video.duration)*100; // console.log(percent); progressBar.style.flexBasis = `${percent}%`; - console.log('autoProgress -- new currentTime: ', video.currentTime); - console.groupEnd(); + // console.log('fill -- new currentTime: ', video.currentTime); + // console.groupEnd(); } } @@ -113,18 +100,18 @@ function scrub(e) { // IE variant e.cancelBubble = true } - console.group('START scrub -- isScrubbing: ', isScrubbing); - console.log('scrub -- old currentTime: ',video.currentTime); + // console.group('START scrub -- isScrubbing: ', isScrubbing); + // console.log('scrub -- old currentTime: ',video.currentTime); video.currentTime = video.duration * (e.offsetX / progress.offsetWidth); progressBar.style.flexBasis = (video.currentTime / video.duration)*100+'%'; - console.log('scrub -- new currentTime: ',video.currentTime); - console.groupEnd(); + // console.log('scrub -- new currentTime: ',video.currentTime); + // console.groupEnd(); } function goFullScreen(e) { - console.log('START goFullScreen'); + // console.log('START goFullScreen'); if (video.requestFullscreen) { - console.log('requestFullscreen'); + // console.log('requestFullscreen'); video.requestFullscreen(); } } @@ -135,7 +122,7 @@ function goFullScreen(e) { video.addEventListener('click',togglePlayer); video.addEventListener('play',toggleButton); video.addEventListener('pause',toggleButton); -video.addEventListener('timeupdate',autoProgress); +video.addEventListener('timeupdate',fill); toggle.addEventListener('click',togglePlayer); diff --git a/11--Custom_Video_Player/style.css b/11--Custom_Video_Player/style.css index 0467f0af11..0dfa078bdf 100644 --- a/11--Custom_Video_Player/style.css +++ b/11--Custom_Video_Player/style.css @@ -13,6 +13,7 @@ body { min-height:100vh; background:linear-gradient(135deg, #7c1599 0%,#921099 50%,#7e4ae8 100%); background-size:cover; + flex-direction:column; align-items:center; justify-content:center; } From 4e329bf1cdbe91600ff5a5472df57b27eb814d5e Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 12:52:11 -0600 Subject: [PATCH 042/119] make full screen button work in pro 11. --- 11--Custom_Video_Player/scripts-jds.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index 21e53d1547..23b4dda2ea 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -108,14 +108,6 @@ function scrub(e) { // console.groupEnd(); } -function goFullScreen(e) { - // console.log('START goFullScreen'); - if (video.requestFullscreen) { - // console.log('requestFullscreen'); - video.requestFullscreen(); - } -} - /** * hook up event listeners */ @@ -128,8 +120,15 @@ toggle.addEventListener('click',togglePlayer); skipButtons.forEach(button => button.addEventListener('click',skip)); -fullScreen.addEventListener('click', () => { - goFullScreen; +fullScreen.addEventListener('click', (e) => { + console.log(e); + var el = video, + rfs = el.requestFullscreen + || el.webkitRequestFullScreen + || el.mozRequestFullScreen + || el.msRequestFullscreen + ; + rfs.call(el); }); ranges.forEach(range => range.addEventListener('change',updateRange)); From e0991b585d222d254f6ec8478d9dd2411ad1c7a6 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 13:01:23 -0600 Subject: [PATCH 043/119] start project 12. --- 12--Key_Sequence_Detection/index-jds.html | 12 ++++++++++++ 12--Key_Sequence_Detection/index.html | 16 ++++++++++++++++ index.html | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 12--Key_Sequence_Detection/index-jds.html create mode 100644 12--Key_Sequence_Detection/index.html diff --git a/12--Key_Sequence_Detection/index-jds.html b/12--Key_Sequence_Detection/index-jds.html new file mode 100644 index 0000000000..8cab786140 --- /dev/null +++ b/12--Key_Sequence_Detection/index-jds.html @@ -0,0 +1,12 @@ + + + + + Key Detection + + + + + + diff --git a/12--Key_Sequence_Detection/index.html b/12--Key_Sequence_Detection/index.html new file mode 100644 index 0000000000..d24962764d --- /dev/null +++ b/12--Key_Sequence_Detection/index.html @@ -0,0 +1,16 @@ + + + + + Key Detection + + + + + + + diff --git a/index.html b/index.html index 7c16e2409d..a8496bea4f 100755 --- a/index.html +++ b/index.html @@ -18,7 +18,7 @@
  • 09 - Dev Tools Domination
  • 10 - Hold Shift and Check Checkboxes
  • 11 - Custom Video Player
  • - +
  • 12 - Key Sequence Detection
  • From ba6428f8092c69a456543e2bf45d5b92625e9232 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 14:04:16 -0600 Subject: [PATCH 044/119] project 12, do konami code w cornily. --- 12--Key_Sequence_Detection/index-jds.html | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/12--Key_Sequence_Detection/index-jds.html b/12--Key_Sequence_Detection/index-jds.html index 8cab786140..5b024ba483 100644 --- a/12--Key_Sequence_Detection/index-jds.html +++ b/12--Key_Sequence_Detection/index-jds.html @@ -6,7 +6,47 @@ + + From d6311df8b08410b4a57b00dcf79a6000d64234a3 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 14:27:00 -0600 Subject: [PATCH 045/119] optimize. --- 12--Key_Sequence_Detection/index-jds.html | 56 +++++++++++++---------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/12--Key_Sequence_Detection/index-jds.html b/12--Key_Sequence_Detection/index-jds.html index 5b024ba483..e52c1e78c0 100644 --- a/12--Key_Sequence_Detection/index-jds.html +++ b/12--Key_Sequence_Detection/index-jds.html @@ -6,44 +6,52 @@ - +

    enter the konami code

    From 0410a30e860d41cadbfc163e132ceb5480344ef6 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 4 Jan 2017 17:00:40 -0600 Subject: [PATCH 046/119] start project 13. finish slide in on scroll script. TODO: slide out on scroll past. --- 13--Slide_in_on_Scroll/debounce.js | 15 +++++ 13--Slide_in_on_Scroll/index-FINISHED.html | 2 +- 13--Slide_in_on_Scroll/index-START.html | 2 +- 13--Slide_in_on_Scroll/index-jds.html | 57 +++++++++++++++++++ 13--Slide_in_on_Scroll/index.html | 16 ++++++ 13--Slide_in_on_Scroll/scripts.js | 31 ++++++++++ 13--Slide_in_on_Scroll/styles.css | 66 ++++++++++++++++++++++ index.html | 2 +- 8 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 13--Slide_in_on_Scroll/debounce.js create mode 100644 13--Slide_in_on_Scroll/index-jds.html create mode 100644 13--Slide_in_on_Scroll/index.html create mode 100644 13--Slide_in_on_Scroll/scripts.js create mode 100644 13--Slide_in_on_Scroll/styles.css diff --git a/13--Slide_in_on_Scroll/debounce.js b/13--Slide_in_on_Scroll/debounce.js new file mode 100644 index 0000000000..cb89b83419 --- /dev/null +++ b/13--Slide_in_on_Scroll/debounce.js @@ -0,0 +1,15 @@ +// console.log('debounce'); +function debounce(func, wait = 20, immediate = true) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; +} diff --git a/13--Slide_in_on_Scroll/index-FINISHED.html b/13--Slide_in_on_Scroll/index-FINISHED.html index bbaf0b6f22..9255ce9104 100644 --- a/13--Slide_in_on_Scroll/index-FINISHED.html +++ b/13--Slide_in_on_Scroll/index-FINISHED.html @@ -2,7 +2,7 @@ - Document + Slide in on Scroll diff --git a/13--Slide_in_on_Scroll/index-START.html b/13--Slide_in_on_Scroll/index-START.html index 12591bad30..aa5d9df9f5 100644 --- a/13--Slide_in_on_Scroll/index-START.html +++ b/13--Slide_in_on_Scroll/index-START.html @@ -2,7 +2,7 @@ - Document + Slide in on Scroll diff --git a/13--Slide_in_on_Scroll/index-jds.html b/13--Slide_in_on_Scroll/index-jds.html new file mode 100644 index 0000000000..fbbb500fbd --- /dev/null +++ b/13--Slide_in_on_Scroll/index-jds.html @@ -0,0 +1,57 @@ + + + + + Slide in on Scroll + + + + +
    + +

    Slide in on Scroll

    + +

    Consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariaturlores sunt esse magni, ut, dignissimos.

    +

    Lorem ipsum cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    +

    Adipisicing elit. Tempore tempora rerum..

    + + + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

    + + + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptates, deserunt facilis et iste corrupti omnis tenetur est. Iste ut est dicta dolor itaque adipisci, dolorum minima, veritatis earum provident error molestias. Ratione magni illo sint vel velit ut excepturi consectetur suscipit, earum modi accusamus voluptatem nostrum, praesentium numquam, reiciendis voluptas sit id quisquam. Consequatur in quis reprehenderit modi perspiciatis necessitatibus saepe, quidem, suscipit iure natus dignissimos ipsam, eligendi deleniti accusantium, rerum quibusdam fugit perferendis et optio recusandae sed ratione. Culpa, dolorum reprehenderit harum ab voluptas fuga, nisi eligendi natus maiores illum quas quos et aperiam aut doloremque optio maxime fugiat doloribus. Eum dolorum expedita quam, nesciunt

    + + + +

    at provident praesentium atque quas rerum optio dignissimos repudiandae ullam illum quibusdam. Vel ad error quibusdam, illo ex totam placeat. Quos excepturi fuga, molestiae ea quisquam minus, ratione dicta consectetur officia omnis, doloribus voluptatibus? Veniam ipsum veritatis architecto, provident quas consequatur doloremque quam quidem earum expedita, ad delectus voluptatum, omnis praesentium nostrum qui aspernatur ea eaque adipisci et cumque ab? Ea voluptatum dolore itaque odio. Eius minima distinctio harum, officia ab nihil exercitationem. Tempora rem nemo nam temporibus molestias facilis minus ipsam quam doloribus consequatur debitis nesciunt tempore officiis aperiam quisquam, molestiae voluptates cum, fuga culpa. Distinctio accusamus quibusdam, tempore perspiciatis dolorum optio facere consequatur quidem ullam beatae architecto, ipsam sequi officiis dignissimos amet impedit natus necessitatibus tenetur repellendus dolor rem! Dicta dolorem, iure, facilis illo ex nihil ipsa amet officia, optio temporibus eum autem odit repellendus nisi. Possimus modi, corrupti error debitis doloribus dicta libero earum, sequi porro ut excepturi nostrum ea voluptatem nihil culpa? Ullam expedita eligendi obcaecati reiciendis velit provident omnis quas qui in corrupti est dolore facere ad hic, animi soluta assumenda consequuntur reprehenderit! Voluptate dolor nihil veniam laborum voluptas nisi pariatur sed optio accusantium quam consectetur, corrupti, sequi et consequuntur, excepturi doloremque. Tempore quis velit corporis neque fugit non sequi eaque rem hic. Facere, inventore, aspernatur. Accusantium modi atque, asperiores qui nobis soluta cumque suscipit excepturi possimus doloremque odit saepe perferendis temporibus molestiae nostrum voluptatum quis id sint quidem nesciunt culpa. Rerum labore dolor beatae blanditiis praesentium explicabo velit optio esse aperiam similique, voluptatem cum, maiores ipsa tempore. Reiciendis sed culpa atque inventore, nam ullam enim expedita consectetur id velit iusto alias vitae explicabo nemo neque odio reprehenderit soluta sint eaque. Aperiam, qui ut tenetur, voluptate doloremque officiis dicta quaerat voluptatem rerum natus magni. Eum amet autem dolor ullam.

    + + + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis

    + + + +

    laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

    + + + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

    + + + +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

    + + + + +
    + + + + + + diff --git a/13--Slide_in_on_Scroll/index.html b/13--Slide_in_on_Scroll/index.html new file mode 100644 index 0000000000..5645cf6089 --- /dev/null +++ b/13--Slide_in_on_Scroll/index.html @@ -0,0 +1,16 @@ + + + + + Slide in on Scroll + + + + + + + diff --git a/13--Slide_in_on_Scroll/scripts.js b/13--Slide_in_on_Scroll/scripts.js new file mode 100644 index 0000000000..1830083903 --- /dev/null +++ b/13--Slide_in_on_Scroll/scripts.js @@ -0,0 +1,31 @@ +// console.log('scripts'); +const body = document.querySelector('body'); +const images = document.querySelectorAll('.slide-in'); +console.log(images); + +body.scrollTop = 0; + +// images.forEach(img => img.classList.add('active')); + +function checkSlide(e) { + console.count(e); + // console.log('window.scrollY: ', window.scrollY); + // console.log('window.innerHeight: ', window.innerHeight); + // console.log('body.clientHeight: ', body.clientHeight); + images.forEach(img => { + // console.group(img.src); + // console.log('image midpoint', (img.offsetTop+(img.clientHeight/4))); + // console.log('current scroll point', (window.scrollY+window.innerHeight)); + // console.groupEnd(); + // console.log('img.offsetTop: ',img.offsetTop); + // console.log('img.clientHeight: ',img.clientHeight); + if ((img.offsetTop+(img.clientHeight/4)) < (window.scrollY+window.innerHeight)) { + console.info(img.src+' is IN VIEW!'); + img.classList.add('active'); + } else { + } + }); +} + +// window.addEventListener('scroll',checkSlide); +window.addEventListener('scroll',debounce(checkSlide)); \ No newline at end of file diff --git a/13--Slide_in_on_Scroll/styles.css b/13--Slide_in_on_Scroll/styles.css new file mode 100644 index 0000000000..3f96074d01 --- /dev/null +++ b/13--Slide_in_on_Scroll/styles.css @@ -0,0 +1,66 @@ +*, *:before, *:after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + box-sizing: border-box; + background:#ffc600; + font-family:'helvetica neue'; + font-size: 100%; + font-weight: 200; +} + +body { + font-size: 1rem; + line-height: 1.4; +} + +h1, p {margin: 1em 1rem;} + +.site-wrap { + font-size: 1.4rem; + margin: 2em 10%; + background:#fff; + box-shadow: + 0 0 0.5em 0 rgba(0,0,0,0.25), + 0 0.5em 2em 0 rgba(0,0,0,0.25); + padding:1em 1rem; + text-align: justify; +} + +img { + margin:0.5rem -2rem; + box-shadow: + 0 0 0.25em 0 rgba(0,0,0,0.5), + 0 0.25em 1em 0 rgba(0,0,0,0.5); +} + +.align-left { + float:left; + margin-right:2rem; +} + +.align-right { + float:right; + margin-left:2rem; +} + +.slide-in { + opacity:0; + transition:all .5s; +} + +.align-left.slide-in { + transform:translateX(-30%) scale(0.9); +} +.align-right.slide-in { + transform:translateX(30%) scale(0.9); +} + +.slide-in.active { + opacity:1; + transform:translateX(0%) scale(1); +} + diff --git a/index.html b/index.html index a8496bea4f..3dce9e07c0 100755 --- a/index.html +++ b/index.html @@ -19,7 +19,7 @@
  • 10 - Hold Shift and Check Checkboxes
  • 11 - Custom Video Player
  • 12 - Key Sequence Detection
  • - +
  • 13 - Slide in on Scroll
  • From 45048e26dd33f2170686957fe085ce8bf1322e42 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 5 Jan 2017 12:48:46 -0600 Subject: [PATCH 047/119] project 13 work... hide image when scrolling past it. show image when scrolling it back into view. --- 13--Slide_in_on_Scroll/debounce.js | 1 - 13--Slide_in_on_Scroll/scripts.js | 45 ++++++++++++++++++------------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/13--Slide_in_on_Scroll/debounce.js b/13--Slide_in_on_Scroll/debounce.js index cb89b83419..eee511e8c2 100644 --- a/13--Slide_in_on_Scroll/debounce.js +++ b/13--Slide_in_on_Scroll/debounce.js @@ -1,4 +1,3 @@ -// console.log('debounce'); function debounce(func, wait = 20, immediate = true) { var timeout; return function() { diff --git a/13--Slide_in_on_Scroll/scripts.js b/13--Slide_in_on_Scroll/scripts.js index 1830083903..ddd16ad568 100644 --- a/13--Slide_in_on_Scroll/scripts.js +++ b/13--Slide_in_on_Scroll/scripts.js @@ -1,31 +1,40 @@ -// console.log('scripts'); +// cache dom objects. const body = document.querySelector('body'); const images = document.querySelectorAll('.slide-in'); -console.log(images); -body.scrollTop = 0; +// give each image an ID for logging purposes. +let count = 0; +images.forEach(img => { + count++; + img.id = count; +}); -// images.forEach(img => img.classList.add('active')); +// return to top of page on refresh/load & clear console. +window.onload = function() { + setTimeout (function () { + scrollTo(0,0); + console.clear(); + }, 100); //100ms for example +} +// check if image is in view or not and show/hide accordingly. function checkSlide(e) { - console.count(e); - // console.log('window.scrollY: ', window.scrollY); - // console.log('window.innerHeight: ', window.innerHeight); - // console.log('body.clientHeight: ', body.clientHeight); images.forEach(img => { - // console.group(img.src); - // console.log('image midpoint', (img.offsetTop+(img.clientHeight/4))); - // console.log('current scroll point', (window.scrollY+window.innerHeight)); - // console.groupEnd(); - // console.log('img.offsetTop: ',img.offsetTop); - // console.log('img.clientHeight: ',img.clientHeight); - if ((img.offsetTop+(img.clientHeight/4)) < (window.scrollY+window.innerHeight)) { - console.info(img.src+' is IN VIEW!'); + console.group('image ',img.id) + const imageMidpoint = (img.offsetTop+(img.clientHeight/2)); + const isInView = (imageMidpoint < window.scrollY+window.innerHeight); + console.log('isInView: ', isInView); + const isOutOfView = (imageMidpoint < window.scrollY); + console.log('isOutOfView: ', isOutOfView); + if (isInView && !isOutOfView) { img.classList.add('active'); } else { + img.classList.remove('active'); } + console.groupEnd(); }); } -// window.addEventListener('scroll',checkSlide); -window.addEventListener('scroll',debounce(checkSlide)); \ No newline at end of file +// listen for scroll event according to interval given to +// debounce function. +window.addEventListener('scroll',debounce(checkSlide,10)); From c69be13182d0eed7492e9aef7a0a36cb9d9fe7e5 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 5 Jan 2017 14:04:29 -0600 Subject: [PATCH 048/119] optimize project 13. --- 13--Slide_in_on_Scroll/scripts.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/13--Slide_in_on_Scroll/scripts.js b/13--Slide_in_on_Scroll/scripts.js index ddd16ad568..135d6d254d 100644 --- a/13--Slide_in_on_Scroll/scripts.js +++ b/13--Slide_in_on_Scroll/scripts.js @@ -20,18 +20,20 @@ window.onload = function() { // check if image is in view or not and show/hide accordingly. function checkSlide(e) { images.forEach(img => { - console.group('image ',img.id) + // console.group('image ',img.id) const imageMidpoint = (img.offsetTop+(img.clientHeight/2)); const isInView = (imageMidpoint < window.scrollY+window.innerHeight); - console.log('isInView: ', isInView); + // console.log('isInView: ', isInView); const isOutOfView = (imageMidpoint < window.scrollY); - console.log('isOutOfView: ', isOutOfView); + // console.log('isOutOfView: ', isOutOfView); if (isInView && !isOutOfView) { + // show when in view AND not out of view img.classList.add('active'); } else { + // hide when NOT in view img.classList.remove('active'); } - console.groupEnd(); + // console.groupEnd(); }); } From 14a2ad3a05566508c9cdd305ae742b4529080fa9 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 5 Jan 2017 14:06:53 -0600 Subject: [PATCH 049/119] project 11: go full screen on double click. --- 11--Custom_Video_Player/scripts-jds.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/11--Custom_Video_Player/scripts-jds.js b/11--Custom_Video_Player/scripts-jds.js index 23b4dda2ea..1440d299bd 100644 --- a/11--Custom_Video_Player/scripts-jds.js +++ b/11--Custom_Video_Player/scripts-jds.js @@ -108,6 +108,16 @@ function scrub(e) { // console.groupEnd(); } +function goFullscreen() { + var el = video, + rfs = el.requestFullscreen + || el.webkitRequestFullScreen + || el.mozRequestFullScreen + || el.msRequestFullscreen + ; + rfs.call(el); +} + /** * hook up event listeners */ @@ -120,16 +130,8 @@ toggle.addEventListener('click',togglePlayer); skipButtons.forEach(button => button.addEventListener('click',skip)); -fullScreen.addEventListener('click', (e) => { - console.log(e); - var el = video, - rfs = el.requestFullscreen - || el.webkitRequestFullScreen - || el.mozRequestFullScreen - || el.msRequestFullscreen - ; - rfs.call(el); -}); +video.addEventListener('dblclick', goFullscreen); +fullScreen.addEventListener('click', goFullscreen); ranges.forEach(range => range.addEventListener('change',updateRange)); From fb29d1aafef525c49cbc387ddfab4009508d85f5 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 5 Jan 2017 14:08:51 -0600 Subject: [PATCH 050/119] start project 14. --- .../index-jds.html | 52 +++++++++++++++++++ .../index.html | 16 ++++++ index.html | 2 +- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 14--JavaScript_References_VS_Copying/index-jds.html create mode 100644 14--JavaScript_References_VS_Copying/index.html diff --git a/14--JavaScript_References_VS_Copying/index-jds.html b/14--JavaScript_References_VS_Copying/index-jds.html new file mode 100644 index 0000000000..4da1bac2ea --- /dev/null +++ b/14--JavaScript_References_VS_Copying/index-jds.html @@ -0,0 +1,52 @@ + + + + + JS Reference VS Copy + + + + + + + diff --git a/14--JavaScript_References_VS_Copying/index.html b/14--JavaScript_References_VS_Copying/index.html new file mode 100644 index 0000000000..10f80b929f --- /dev/null +++ b/14--JavaScript_References_VS_Copying/index.html @@ -0,0 +1,16 @@ + + + + + JS Reference VS Copy + + + + + + + diff --git a/index.html b/index.html index 3dce9e07c0..9f8fea8898 100755 --- a/index.html +++ b/index.html @@ -20,7 +20,7 @@
  • 11 - Custom Video Player
  • 12 - Key Sequence Detection
  • 13 - Slide in on Scroll
  • - +
  • 14 - JavaScript References VS Copying
  • From 9f511109c53cbbecc883cdaaad55c01b71e7d7a6 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 5 Jan 2017 14:47:46 -0600 Subject: [PATCH 051/119] finish lesson 14. --- .../index-jds.html | 70 +++++++++++++++++-- index.html | 2 +- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/14--JavaScript_References_VS_Copying/index-jds.html b/14--JavaScript_References_VS_Copying/index-jds.html index 4da1bac2ea..d6dd75cfc1 100644 --- a/14--JavaScript_References_VS_Copying/index-jds.html +++ b/14--JavaScript_References_VS_Copying/index-jds.html @@ -8,43 +8,105 @@ diff --git a/index.html b/index.html index 9f8fea8898..1263d2e1ae 100755 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - JS Drum Kit + Project Index From 0603cea12304ee9c4fe3328c20c6df2513b8b8b3 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 9 Jan 2017 10:48:24 -0600 Subject: [PATCH 052/119] Start project 15. --- 15--LocalStorage/index-jds.html | 56 +++++++++++++++++++++++++++++++++ 15--LocalStorage/index.html | 16 ++++++++++ 15--LocalStorage/style.css | 2 +- index.html | 2 +- 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 15--LocalStorage/index-jds.html create mode 100644 15--LocalStorage/index.html diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html new file mode 100644 index 0000000000..3292b8e984 --- /dev/null +++ b/15--LocalStorage/index-jds.html @@ -0,0 +1,56 @@ + + + + + LocalStorage + + + + + + + +
    +

    LOCAL TAPAS

    +

    +
      +
    • Loading Tapas...
    • +
    +
    + + +
    +
    + + + + + + + diff --git a/15--LocalStorage/index.html b/15--LocalStorage/index.html new file mode 100644 index 0000000000..0e2811402c --- /dev/null +++ b/15--LocalStorage/index.html @@ -0,0 +1,16 @@ + + + + + LocalStorage + + + + + + + diff --git a/15--LocalStorage/style.css b/15--LocalStorage/style.css index ea5bab179c..85d75efd66 100644 --- a/15--LocalStorage/style.css +++ b/15--LocalStorage/style.css @@ -1,7 +1,7 @@ html { box-sizing: border-box; - background:url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat; + // background:url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat; background-size:cover; min-height:100vh; display:flex; diff --git a/index.html b/index.html index 1263d2e1ae..3ee78e7e2f 100755 --- a/index.html +++ b/index.html @@ -21,7 +21,7 @@
  • 12 - Key Sequence Detection
  • 13 - Slide in on Scroll
  • 14 - JavaScript References VS Copying
  • - +
  • 15 - LocalStorage
  • From ec476b08703c9c02852b09ef0bd91ac829064ce2 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 9 Jan 2017 12:17:33 -0600 Subject: [PATCH 053/119] Add input item to array. --- 15--LocalStorage/index-jds.html | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html index 3292b8e984..1a18c99056 100644 --- a/15--LocalStorage/index-jds.html +++ b/15--LocalStorage/index-jds.html @@ -17,7 +17,7 @@

    LOCAL TAPAS

      -
    • Loading Tapas...
    • +
    • Loading Tapas...
    @@ -42,11 +42,38 @@

    LOCAL TAPAS

    * Functions */ +function addItem(e) { + console.group('START addItem'); + e.preventDefault(); + // console.log('e: ',e); + // console.log('e.target: ',e.target); + // console.log('e.target[0].value: ',e.target[0].value); + const item = { + // text:e.target[0].value, + text:this.querySelector('[name=item]').value, + done:false + }; + items.push(item); + console.log(items); + console.groupEnd(); +} + /** * Event Listeners */ +addItems.addEventListener('submit',addItem); +// addItems.addEventListener('submit',(e)=>{ +// addItem(e); +// }); +document.querySelector('.plates').addEventListener('click',(e)=>{ + console.log(e.target); + if(e.target && e.target.nodeName == "LI") { + // List item found! Output the ID! + console.log("List item \""+e.target.id+"\" was clicked!"); + } +}) From b60e6a5e689dd31905a9c6ba5fa20fe53d27143d Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 9 Jan 2017 13:31:07 -0600 Subject: [PATCH 054/119] populate HTML list and add items to local storage. --- 15--LocalStorage/index-jds.html | 38 +++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html index 1a18c99056..61c06c317a 100644 --- a/15--LocalStorage/index-jds.html +++ b/15--LocalStorage/index-jds.html @@ -27,10 +27,10 @@

    LOCAL TAPAS

    - diff --git a/15--LocalStorage/style.css b/15--LocalStorage/style.css index 85d75efd66..e8cd4d48a0 100644 --- a/15--LocalStorage/style.css +++ b/15--LocalStorage/style.css @@ -1,78 +1,78 @@ - html { - box-sizing: border-box; - // background:url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat; - background-size:cover; - min-height:100vh; - display:flex; - justify-content: center; - align-items: center; - text-align: center; - font-family: Futura,"Trebuchet MS",Arial,sans-serif - } - *, *:before, *:after {box-sizing: inherit; } +html { + box-sizing: border-box; + // background:url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat; + background-size:cover; + min-height:100vh; + display:flex; + justify-content: center; + align-items: center; + text-align: center; + font-family: Futura,"Trebuchet MS",Arial,sans-serif +} +*, *:before, *:after {box-sizing: inherit; } - svg { - fill:white; - background: rgba(0,0,0,0.1); - padding: 20px; - border-radius: 50%; - width:200px; - margin-bottom: 50px; - } +svg { + fill:white; + background: rgba(0,0,0,0.1); + padding: 20px; + border-radius: 50%; + width:200px; + margin-bottom: 50px; +} - .wrapper { - padding: 20px; - max-width: 350px; - background: rgba(255,255,255,0.95); - box-shadow: 0 0 0 10px rgba(0,0,0,0.1); - } +.wrapper { + padding: 20px; + max-width: 350px; + background: rgba(255,255,255,0.95); + box-shadow: 0 0 0 10px rgba(0,0,0,0.1); +} - h2 { - text-align: center; - margin: 0; - font-weight: 200; - } +h2 { + text-align: center; + margin: 0; + font-weight: 200; +} - .plates { - margin: 0; - padding: 0; - text-align: left; - list-style: none; - } +.plates { + margin: 0; + padding: 0; + text-align: left; + list-style: none; +} - .plates li { - border-bottom: 1px solid rgba(0,0,0,0.2); - padding: 10px 0; - font-weight: 100; - display: flex; - } +.plates li { + border-bottom: 1px solid rgba(0,0,0,0.2); + padding: 10px 0; + font-weight: 100; + display: flex; +} - .plates label { - flex:1; - cursor: pointer; +.plates label { + flex:1; + cursor: pointer; - } +} - .plates input { - display: none; - } +.plates input { + display: none; +} - .plates input + label:before { - content: '⬜️'; - margin-right: 10px; - } +.plates input + label:before { + content: '⬜️'; + margin-right: 10px; +} - .plates input:checked + label:before { - content: '🌮'; - } +.plates input:checked + label:before { + content: '🌮'; +} - .add-items { - margin-top: 20px; - } +.add-items { + margin-top: 20px; +} - .add-items input { - padding:10px; - outline:0; - border:1px solid rgba(0,0,0,0.1); - } +.add-items input { + padding:10px; + outline:0; + border:1px solid rgba(0,0,0,0.1); +} From 93d65a41fae9e82cfeb4b2a5d837f222fc89f011 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 9 Jan 2017 15:21:45 -0600 Subject: [PATCH 056/119] rearrange function. --- 15--LocalStorage/index-jds.html | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html index ba21a822e1..c585b776cc 100644 --- a/15--LocalStorage/index-jds.html +++ b/15--LocalStorage/index-jds.html @@ -90,7 +90,14 @@

    LOCAL TAPAS

    function toggleItem(e) { console.log('START toggleItem'); - console.log(this); + if (e.target.tagName === 'INPUT') { + console.log('e.target.id: ', e.target.id); + console.log(items[e.target.dataset.index].done); + items[e.target.dataset.index].done = !items[e.target.dataset.index].done; + console.log(items[e.target.dataset.index].done); + console.log('items: ', items); + localStorage.setItem('items',JSON.stringify(items)); + } } @@ -101,18 +108,7 @@

    LOCAL TAPAS

    addItems.addEventListener('submit',addItem); // itemsList.querySelectorAll('[type=checkbox]').forEach(thing => thing.addEventListener('change',toggleItem)); -document.querySelector('body').addEventListener('click',(e)=>{ - // toggleItem(); - // e.stopPropagation(); - if (e.target.tagName === 'INPUT') { - console.log('e.target.id: ', e.target.id); - console.log(items[e.target.dataset.index].done); - items[e.target.dataset.index].done = !items[e.target.dataset.index].done; - console.log(items[e.target.dataset.index].done); - console.log('items: ', items); - localStorage.setItem('items',JSON.stringify(items)); - } -}); +itemsList.addEventListener('click',toggleItem); populateList(items,itemsList); From f8fa3d2e6435f3066083b0ba6ad3cf9bb04a9bed Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 9 Jan 2017 15:48:44 -0600 Subject: [PATCH 057/119] finish proj 15. --- 15--LocalStorage/index-jds.html | 59 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html index c585b776cc..48a6d17f4a 100644 --- a/15--LocalStorage/index-jds.html +++ b/15--LocalStorage/index-jds.html @@ -1,10 +1,13 @@ + + LocalStorage + - + + + + + +

    LOCAL TAPAS

    @@ -24,11 +29,15 @@

    LOCAL TAPAS

  • Loading Tapas...
- - - - - +
+ + +
+
+ + + +
diff --git a/15--LocalStorage/style.css b/15--LocalStorage/style.css index e8cd4d48a0..44c6b07aac 100644 --- a/15--LocalStorage/style.css +++ b/15--LocalStorage/style.css @@ -1,6 +1,10 @@ +*, *:before, *:after { + margin: 0; + padding: 0; + box-sizing: border-box; +} html { - box-sizing: border-box; // background:url('http://wes.io/hx9M/oh-la-la.jpg') center no-repeat; background-size:cover; min-height:100vh; @@ -10,7 +14,6 @@ html { text-align: center; font-family: Futura,"Trebuchet MS",Arial,sans-serif } -*, *:before, *:after {box-sizing: inherit; } svg { fill:white; @@ -28,6 +31,8 @@ svg { box-shadow: 0 0 0 10px rgba(0,0,0,0.1); } +fieldset {border:0; margin:0.5em 0 0; text-align:center;} + h2 { text-align: center; margin: 0; From 5d8c6f620a364741f0933e180547e6a0f73beda9 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 10:32:27 -0600 Subject: [PATCH 060/119] streamline extra credit function. --- 15--LocalStorage/index-jds.html | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/15--LocalStorage/index-jds.html b/15--LocalStorage/index-jds.html index 17bf3db3e3..d8d8669639 100644 --- a/15--LocalStorage/index-jds.html +++ b/15--LocalStorage/index-jds.html @@ -122,25 +122,28 @@

LOCAL TAPAS

populateList(items,itemsList); } -function fnCheck() { - console.log('START fnCheck'); - items.forEach(item => item.done=true) - localStorage.setItem('items',JSON.stringify(items)); - populateList(items,itemsList); -} - -function fnUncheck() { - console.log('START fnUncheck'); - items.forEach(item => item.done=false) - localStorage.setItem('items',JSON.stringify(items)); - populateList(items,itemsList); -} - -function fnDelete() { - console.log('START fnDelete'); - items.splice(0,items.length); +function fnCool(type) { + console.group('START fnCool'); + switch(type) { + case 'check': + console.log('check'); + items.forEach(item => item.done=true); + break; + case 'uncheck': + console.log('uncheck'); + items.forEach(item => item.done=false); + break; + case 'delete': + console.log('delete'); + items.splice(0,items.length); + break; + default: + console.log('default'); + break; + } localStorage.setItem('items',JSON.stringify(items)); populateList(items,itemsList); + console.groupEnd(); } /** @@ -150,9 +153,9 @@

LOCAL TAPAS

itemsList.addEventListener('click',toggleItem); -btnCheck.addEventListener('click',fnCheck); -btnUncheck.addEventListener('click',fnUncheck); -btnDelete.addEventListener('click',fnDelete); +btnCheck.addEventListener('click',()=>{fnCool('check')}); +btnUncheck.addEventListener('click',()=>{fnCool('uncheck')}); +btnDelete.addEventListener('click',()=>{fnCool('delete')}); populateList(items,itemsList); From 76a1e4504ebab2b0560e84a7e75f321db1a3889b Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 11:43:22 -0600 Subject: [PATCH 061/119] start prject 16. first attempt w no guidance. --- 16--Mouse_Move_Shadow/debounce.js | 14 ++++++++ 16--Mouse_Move_Shadow/index-jds.html | 54 ++++++++++++++++++++++++++++ 16--Mouse_Move_Shadow/index.html | 16 +++++++++ index.html | 2 +- 4 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 16--Mouse_Move_Shadow/debounce.js create mode 100644 16--Mouse_Move_Shadow/index-jds.html create mode 100644 16--Mouse_Move_Shadow/index.html diff --git a/16--Mouse_Move_Shadow/debounce.js b/16--Mouse_Move_Shadow/debounce.js new file mode 100644 index 0000000000..eee511e8c2 --- /dev/null +++ b/16--Mouse_Move_Shadow/debounce.js @@ -0,0 +1,14 @@ +function debounce(func, wait = 20, immediate = true) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + var callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) func.apply(context, args); + }; +} diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html new file mode 100644 index 0000000000..39204fde60 --- /dev/null +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -0,0 +1,54 @@ + + + + + Mouse Shadow + + + +
+

🔥WOAH!

+
+ + + + + + + diff --git a/16--Mouse_Move_Shadow/index.html b/16--Mouse_Move_Shadow/index.html new file mode 100644 index 0000000000..a8eb8ed529 --- /dev/null +++ b/16--Mouse_Move_Shadow/index.html @@ -0,0 +1,16 @@ + + + + + Mouse Shadow + + + + + + + diff --git a/index.html b/index.html index 3ee78e7e2f..f1dee88541 100755 --- a/index.html +++ b/index.html @@ -22,7 +22,7 @@
  • 13 - Slide in on Scroll
  • 14 - JavaScript References VS Copying
  • 15 - LocalStorage
  • - +
  • 16 - Mouse Move Shadow
  • From 3b06b4a713a2334cd9da9d05b9ff1f54fc0f1769 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 12:28:43 -0600 Subject: [PATCH 062/119] use hero.offset* to get w and h. --- 16--Mouse_Move_Shadow/index-jds.html | 38 ++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html index 39204fde60..2a0866478c 100644 --- a/16--Mouse_Move_Shadow/index-jds.html +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -25,30 +25,46 @@

    🔥WOAH!

    } h1 { - text-shadow: 10px 10px 0 rgba(0,0,0,1); + text-shadow: 10px 10px 0 rgba(0,0,0,0.75); + text-shadow: + 15px 0px 0 rgba(255,255,0,0.75), + 0px 15px 0 rgba(0,255,255,0.75), + -15px -0px 0 rgba(255,0,255,0.75), + -0px -15px 0 rgba(0,255,0,0.75); font-size: 100px; } From e986e073c37a2194d4026ef090242eb9bc593359 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 13:13:15 -0600 Subject: [PATCH 063/119] calculate shadow x & y my own way. shadows rotate opposite to mouse. --- 16--Mouse_Move_Shadow/index-jds.html | 82 +++++++++++++++------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html index 2a0866478c..9f9663bb9f 100644 --- a/16--Mouse_Move_Shadow/index-jds.html +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -7,32 +7,40 @@
    -

    🔥WOAH!

    +

    cmyk

    @@ -42,28 +50,28 @@

    🔥WOAH!

    const header = hero.querySelector('h1'); function fnShadowEffect(e) { - console.log(e); + // console.log(this); + // console.log(e); console.log('W:'+hero.offsetWidth+' / H:'+hero.offsetHeight); console.log('X:'+e.clientX+' / Y:'+e.clientY); - const x = e.clientX-(hero.offsetWidth/2); - console.log(x); - const y = e.clientY-(hero.offsetHeight/2); - console.log(y); - // console.log(header.style.textShadow); - // if (e.srcElement.nodeName === 'H1') { - header.style.textShadow = ` - ${-x}px ${y}px 0 rgba(255,255,0,0.75), - ${y}px ${-x}px 0 rgba(0,255,255,0.75), - ${x}px ${-y}px 0 rgba(255,0,255,0.75), - ${-y}px ${x}px 0 rgba(0,255,0,0.75) - `; - // } else { - // header.style.textShadow = ``; - // } + const x = Math.round((e.clientX-(hero.offsetWidth/2))/hero.offsetWidth * 200); + const y = Math.round((e.clientY-(hero.offsetHeight/2))/hero.offsetHeight * 200); + console.log(x, y); + // if (this !== e.target) {} else {} + header.style.textShadow = ` + ${-x}px ${y}px 0 rgba(255,255,0,0.75), + ${y}px ${x}px 0 rgba(0,255,255,0.75), + ${x}px ${-y}px 0 rgba(255,0,255,0.75), + ${-y}px ${-x}px 0 rgba(0,0,0,0.75) + `; +} +function fnShadowReset(e) { + header.style.textShadow = ``; } // hero.addEventListener('mousemove',debounce(fnShadowEffect)); hero.addEventListener('mousemove',fnShadowEffect); +document.addEventListener('mouseout',fnShadowReset); From d1590e741be0c7aea1ece9a738adb75c8861f9f0 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 13:21:35 -0600 Subject: [PATCH 064/119] use destructured variable assignment. --- 16--Mouse_Move_Shadow/index-jds.html | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html index 9f9663bb9f..eb959f9532 100644 --- a/16--Mouse_Move_Shadow/index-jds.html +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -52,10 +52,21 @@

    cmyk

    function fnShadowEffect(e) { // console.log(this); // console.log(e); - console.log('W:'+hero.offsetWidth+' / H:'+hero.offsetHeight); - console.log('X:'+e.clientX+' / Y:'+e.clientY); - const x = Math.round((e.clientX-(hero.offsetWidth/2))/hero.offsetWidth * 200); - const y = Math.round((e.clientY-(hero.offsetHeight/2))/hero.offsetHeight * 200); + // screen W & H: + // const screenW = hero.offsetWidth; + // const screenH = hero.offsetHeight; + const {offsetWidth : screenW, offsetHeight : screenH} = hero; // destructured assignment + console.log('W:'+screenW+' / H:'+screenH); + // mouse position on screen: + // const mouseX = e.clientX; + // const mouseY = e.clientY; + const {clientX : mouseX, clientY : mouseY} = e; // destructured assignment + console.log('X:'+mouseX+' / Y:'+mouseY); + // x and y are relative to the center of the screen, + // and converted to a percentage, then multiplied by a "walk". + const walk = 200; // max number of pixels shadows can walk. + const x = Math.round((mouseX-(screenW/2))/screenW * walk); + const y = Math.round((mouseY-(screenH/2))/screenH * walk); console.log(x, y); // if (this !== e.target) {} else {} header.style.textShadow = ` From bd78fea6e0163e46c29bba30010b9c3ef8345918 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 13:26:25 -0600 Subject: [PATCH 065/119] finish proj 16. --- 16--Mouse_Move_Shadow/index-jds.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html index eb959f9532..35850248a2 100644 --- a/16--Mouse_Move_Shadow/index-jds.html +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -32,7 +32,7 @@

    cmyk

    } h1 { - text-shadow: 10px 10px 0 rgba(0,0,0,0.75); + /* text-shadow: 10px 10px 0 rgba(0,0,0,0.75); */ text-shadow: 10px 0px 0 rgba(255,255,0,0.75), 0px 10px 0 rgba(0,255,255,0.75), @@ -56,18 +56,18 @@

    cmyk

    // const screenW = hero.offsetWidth; // const screenH = hero.offsetHeight; const {offsetWidth : screenW, offsetHeight : screenH} = hero; // destructured assignment - console.log('W:'+screenW+' / H:'+screenH); + // console.log('W:'+screenW+' / H:'+screenH); // mouse position on screen: // const mouseX = e.clientX; // const mouseY = e.clientY; const {clientX : mouseX, clientY : mouseY} = e; // destructured assignment - console.log('X:'+mouseX+' / Y:'+mouseY); + // console.log('X:'+mouseX+' / Y:'+mouseY); // x and y are relative to the center of the screen, // and converted to a percentage, then multiplied by a "walk". const walk = 200; // max number of pixels shadows can walk. const x = Math.round((mouseX-(screenW/2))/screenW * walk); const y = Math.round((mouseY-(screenH/2))/screenH * walk); - console.log(x, y); + console.log(x+'x', y+'y'); // if (this !== e.target) {} else {} header.style.textShadow = ` ${-x}px ${y}px 0 rgba(255,255,0,0.75), @@ -81,8 +81,8 @@

    cmyk

    } // hero.addEventListener('mousemove',debounce(fnShadowEffect)); -hero.addEventListener('mousemove',fnShadowEffect); -document.addEventListener('mouseout',fnShadowReset); +hero.addEventListener('mousemove',fnShadowEffect); // do shadow effect while mouse is over hero. +hero.addEventListener('mouseout',fnShadowReset); // reset shadow effect when mouse leaves hero. From 2a2e9964b1df48fc712e4764aab01a36ef1fb0aa Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 14:06:08 -0600 Subject: [PATCH 066/119] start project #17. clean up #16. #17 is not right. --- 16--Mouse_Move_Shadow/debounce.js | 14 ----- 16--Mouse_Move_Shadow/index-jds.html | 1 - 17--Sort_Without_Articles/index-jds.html | 75 ++++++++++++++++++++++++ 17--Sort_Without_Articles/index.html | 16 +++++ index.html | 2 +- 5 files changed, 92 insertions(+), 16 deletions(-) delete mode 100644 16--Mouse_Move_Shadow/debounce.js create mode 100644 17--Sort_Without_Articles/index-jds.html create mode 100644 17--Sort_Without_Articles/index.html diff --git a/16--Mouse_Move_Shadow/debounce.js b/16--Mouse_Move_Shadow/debounce.js deleted file mode 100644 index eee511e8c2..0000000000 --- a/16--Mouse_Move_Shadow/debounce.js +++ /dev/null @@ -1,14 +0,0 @@ -function debounce(func, wait = 20, immediate = true) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; -} diff --git a/16--Mouse_Move_Shadow/index-jds.html b/16--Mouse_Move_Shadow/index-jds.html index 35850248a2..4b30733dae 100644 --- a/16--Mouse_Move_Shadow/index-jds.html +++ b/16--Mouse_Move_Shadow/index-jds.html @@ -43,7 +43,6 @@

    cmyk

    } - + + + diff --git a/17--Sort_Without_Articles/index.html b/17--Sort_Without_Articles/index.html new file mode 100644 index 0000000000..2f26c927c7 --- /dev/null +++ b/17--Sort_Without_Articles/index.html @@ -0,0 +1,16 @@ + + + + + Sort Without Articles + + + + + + + diff --git a/index.html b/index.html index f1dee88541..d8d227ae30 100755 --- a/index.html +++ b/index.html @@ -23,7 +23,7 @@
  • 14 - JavaScript References VS Copying
  • 15 - LocalStorage
  • 16 - Mouse Move Shadow
  • - +
  • 17 - Sort Without Articles
  • From dedfd38037c14dbfc60d25cda797bc86a57f7bd2 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 15:17:56 -0600 Subject: [PATCH 067/119] get hint: use Array.sort() for #17. got array sorted properly. TODO: display in HTML. --- 17--Sort_Without_Articles/index-jds.html | 48 ++++++++++++++---------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/17--Sort_Without_Articles/index-jds.html b/17--Sort_Without_Articles/index-jds.html index 9f9f5e20c7..e9cdd98e8e 100644 --- a/17--Sort_Without_Articles/index-jds.html +++ b/17--Sort_Without_Articles/index-jds.html @@ -45,28 +45,38 @@ From c64a8a624339b6852d2397fbd72faf42ba6e7557 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 15:20:45 -0600 Subject: [PATCH 068/119] finish #17: display band in HTML. --- 17--Sort_Without_Articles/index-jds.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/17--Sort_Without_Articles/index-jds.html b/17--Sort_Without_Articles/index-jds.html index e9cdd98e8e..fab9d4e56f 100644 --- a/17--Sort_Without_Articles/index-jds.html +++ b/17--Sort_Without_Articles/index-jds.html @@ -43,6 +43,8 @@
      From 2950c173b2ad322407cf95e3cf5659fffc274020 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 15:30:17 -0600 Subject: [PATCH 069/119] slightly optimize #17. --- 17--Sort_Without_Articles/index-jds.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/17--Sort_Without_Articles/index-jds.html b/17--Sort_Without_Articles/index-jds.html index fab9d4e56f..86874456e0 100644 --- a/17--Sort_Without_Articles/index-jds.html +++ b/17--Sort_Without_Articles/index-jds.html @@ -48,12 +48,11 @@ const bands = ['The Plot in You', 'The Devil Wears Prada', 'Pierce the Veil', 'Norma Jean', 'The Bled', 'Say Anything', 'The Midway State', 'We Came as Romans', 'Counterparts', 'Oh, Sleeper', 'A Skylit Drive', 'Anywhere But Here', 'An Old Dog']; console.log(bands); -const articlesArr = ['a ','an ','the ']; -const articlesRegex = /^a\s|^an\s|^the\s/gi; +const articlesRegex = /^(a\s|an\s|the\s)/gi; -const bandsSorted = bands.sort(function(a,b){ +const bandsSorted = bands.sort((a,b) => { console.group('START bandsSorted'); - console.log(a+' || '+b); + // console.log(a+' || '+b); // console.log(a.match(articlesRegex)); const aStart = a.match(articlesRegex)!==null ? a.match(articlesRegex)[0].length : 0; @@ -81,10 +80,10 @@ }); console.log(bandsSorted); -list.innerHTML = bandsSorted.map(band => { - return ` -
    • ${band}
    • - `}).join(''); +list.innerHTML = + bandsSorted + .map(band => `
    • ${band}
    • `) + .join(''); From 925813a175be28076eced0192fbe31d3c9a4c110 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Tue, 10 Jan 2017 15:42:12 -0600 Subject: [PATCH 070/119] done with #17. --- 17--Sort_Without_Articles/index-jds.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/17--Sort_Without_Articles/index-jds.html b/17--Sort_Without_Articles/index-jds.html index 86874456e0..13908de744 100644 --- a/17--Sort_Without_Articles/index-jds.html +++ b/17--Sort_Without_Articles/index-jds.html @@ -54,14 +54,14 @@ console.group('START bandsSorted'); // console.log(a+' || '+b); - // console.log(a.match(articlesRegex)); + // get index of where article (regex) starts or 0... const aStart = a.match(articlesRegex)!==null ? a.match(articlesRegex)[0].length : 0; - // console.log(aStart); + // get substring a = a.substr(aStart); - // console.log(b.match(articlesRegex)); + // get index of where article (regex) starts or 0... const bStart = b.match(articlesRegex)!==null ? b.match(articlesRegex)[0].length : 0; - // console.log(bStart); + // get substring b = b.substr(bStart); console.log(a+' || '+b); From 2aa84be8f35af9b66edad762c50ac8d283951785 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 11 Jan 2017 11:31:29 -0600 Subject: [PATCH 071/119] start and attempt to finish project 18. --- .../index-FINISHED.html | 2 +- .../index-START.html | 2 +- .../index-jds.html | 108 ++++++++++++++++++ 18--Adding_Up_Times_with_Reduce/index.html | 16 +++ 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 18--Adding_Up_Times_with_Reduce/index-jds.html create mode 100644 18--Adding_Up_Times_with_Reduce/index.html diff --git a/18--Adding_Up_Times_with_Reduce/index-FINISHED.html b/18--Adding_Up_Times_with_Reduce/index-FINISHED.html index 9dcbb3d396..cba50ced88 100644 --- a/18--Adding_Up_Times_with_Reduce/index-FINISHED.html +++ b/18--Adding_Up_Times_with_Reduce/index-FINISHED.html @@ -2,7 +2,7 @@ - Videos + Adding up Video Lengths
        diff --git a/18--Adding_Up_Times_with_Reduce/index-START.html b/18--Adding_Up_Times_with_Reduce/index-START.html index 3eaee0f3ef..824c953a40 100644 --- a/18--Adding_Up_Times_with_Reduce/index-START.html +++ b/18--Adding_Up_Times_with_Reduce/index-START.html @@ -2,7 +2,7 @@ - Videos + Adding up Video Lengths
          diff --git a/18--Adding_Up_Times_with_Reduce/index-jds.html b/18--Adding_Up_Times_with_Reduce/index-jds.html new file mode 100644 index 0000000000..e5ae4d2eb0 --- /dev/null +++ b/18--Adding_Up_Times_with_Reduce/index-jds.html @@ -0,0 +1,108 @@ + + + + + Adding up Video Lengths + + +
            +
          • Video 1
          • +
          • Video 2
          • +
          • Video 3
          • +
          • Video 4
          • +
          • Video 5
          • +
          • Video 6
          • +
          • Video 7
          • +
          • Video 8
          • +
          • Video 9
          • +
          • Video 10
          • +
          • Video 11
          • +
          • Video 12
          • +
          • Video 13
          • +
          • Video 14
          • +
          • Video 15
          • +
          • Video 16
          • +
          • Video 17
          • +
          • Video 18
          • +
          • Video 19
          • +
          • Video 20
          • +
          • Video 21
          • +
          • Video 22
          • +
          • Video 23
          • +
          • Video 24
          • +
          • Video 25
          • +
          • Video 26
          • +
          • Video 27
          • +
          • Video 28
          • +
          • Video 29
          • +
          • Video 30
          • +
          • Video 31
          • +
          • Video 32
          • +
          • Video 33
          • +
          • Video 34
          • +
          • Video 35
          • +
          • Video 36
          • +
          • Video 37
          • +
          • Video 38
          • +
          • Video 39
          • +
          • Video 40
          • +
          • Video 41
          • +
          • Video 42
          • +
          • Video 43
          • +
          • Video 44
          • +
          • Video 45
          • +
          • Video 46
          • +
          • Video 47
          • +
          • Video 48
          • +
          • Video 49
          • +
          • Video 50
          • +
          • Video 51
          • +
          • Video 52
          • +
          • Video 53
          • +
          • Video 54
          • +
          • Video 55
          • +
          • Video 56
          • +
          • Video 57
          • +
          • Video 58
          • + + + + diff --git a/18--Adding_Up_Times_with_Reduce/index.html b/18--Adding_Up_Times_with_Reduce/index.html new file mode 100644 index 0000000000..bfca19ee24 --- /dev/null +++ b/18--Adding_Up_Times_with_Reduce/index.html @@ -0,0 +1,16 @@ + + + + + Adding up Video Lengths + + + + + + + From 344c36c705b87ffd6860115d6315cd5c18e74969 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 11 Jan 2017 11:50:44 -0600 Subject: [PATCH 072/119] finish proj 18 w/o watching video. --- .../index-jds.html | 158 ++++++++++-------- 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/18--Adding_Up_Times_with_Reduce/index-jds.html b/18--Adding_Up_Times_with_Reduce/index-jds.html index e5ae4d2eb0..97a036d8c3 100644 --- a/18--Adding_Up_Times_with_Reduce/index-jds.html +++ b/18--Adding_Up_Times_with_Reduce/index-jds.html @@ -6,71 +6,76 @@
              -
            • Video 1
            • -
            • Video 2
            • -
            • Video 3
            • -
            • Video 4
            • -
            • Video 5
            • -
            • Video 6
            • -
            • Video 7
            • -
            • Video 8
            • -
            • Video 9
            • -
            • Video 10
            • -
            • Video 11
            • -
            • Video 12
            • -
            • Video 13
            • -
            • Video 14
            • -
            • Video 15
            • -
            • Video 16
            • -
            • Video 17
            • -
            • Video 18
            • -
            • Video 19
            • -
            • Video 20
            • -
            • Video 21
            • -
            • Video 22
            • -
            • Video 23
            • -
            • Video 24
            • -
            • Video 25
            • -
            • Video 26
            • -
            • Video 27
            • -
            • Video 28
            • -
            • Video 29
            • -
            • Video 30
            • -
            • Video 31
            • -
            • Video 32
            • -
            • Video 33
            • -
            • Video 34
            • -
            • Video 35
            • -
            • Video 36
            • -
            • Video 37
            • -
            • Video 38
            • -
            • Video 39
            • -
            • Video 40
            • -
            • Video 41
            • -
            • Video 42
            • -
            • Video 43
            • -
            • Video 44
            • -
            • Video 45
            • -
            • Video 46
            • -
            • Video 47
            • -
            • Video 48
            • -
            • Video 49
            • -
            • Video 50
            • -
            • Video 51
            • -
            • Video 52
            • -
            • Video 53
            • -
            • Video 54
            • -
            • Video 55
            • -
            • Video 56
            • -
            • Video 57
            • -
            • Video 58
            • - +
            • Video 1 +
            • Video 2 +
            • Video 3 +
            • Video 4 +
            • Video 5 +
            • Video 6 +
            • Video 7 +
            • Video 8 +
            • Video 9 +
            • Video 10 +
            • Video 11 +
            • Video 12 +
            • Video 13 +
            • Video 14 +
            • Video 15 +
            • Video 16 +
            • Video 17 +
            • Video 18 +
            • Video 19 +
            • Video 20 +
            • Video 21 +
            • Video 22 +
            • Video 23 +
            • Video 24 +
            • Video 25 +
            • Video 26 +
            • Video 27 +
            • Video 28 +
            • Video 29 +
            • Video 30 +
            • Video 31 +
            • Video 32 +
            • Video 33 +
            • Video 34 +
            • Video 35 +
            • Video 36 +
            • Video 37 +
            • Video 38 +
            • Video 39 +
            • Video 40 +
            • Video 41 +
            • Video 42 +
            • Video 43 +
            • Video 44 +
            • Video 45 +
            • Video 46 +
            • Video 47 +
            • Video 48 +
            • Video 49 +
            • Video 50 +
            • Video 51 +
            • Video 52 +
            • Video 53 +
            • Video 54 +
            • Video 55 +
            • Video 56 +
            • Video 57 +
            • Video 58 +
            From b356bfac0b69bd65e10e167fa7ab2fd0f9feec62 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Wed, 11 Jan 2017 11:59:06 -0600 Subject: [PATCH 073/119] simplify proj 18. --- .../index-jds.html | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/18--Adding_Up_Times_with_Reduce/index-jds.html b/18--Adding_Up_Times_with_Reduce/index-jds.html index 97a036d8c3..1b9a46df99 100644 --- a/18--Adding_Up_Times_with_Reduce/index-jds.html +++ b/18--Adding_Up_Times_with_Reduce/index-jds.html @@ -67,10 +67,8 @@
          + + + diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html new file mode 100755 index 0000000000..43bd0dab83 --- /dev/null +++ b/19--Webcam_Fun/index-jds.html @@ -0,0 +1,69 @@ + + + + + Webcam Fun -- Get User Media Code Along! + + + + +
          +
          Camera + + +
          +
          Experimental + + + + + + + + + + + + + + + + +
          RedGreenBlue
          + + + + + + + + +
          + + + + + + + + +
          +
          +
          Photo + +
          +
          + +
          + + +
          +
          + + + + + + + + diff --git a/19--Webcam_Fun/index.html b/19--Webcam_Fun/index.html index d4ffc4dc2a..3c6bb70ddb 100755 --- a/19--Webcam_Fun/index.html +++ b/19--Webcam_Fun/index.html @@ -2,44 +2,15 @@ - Get User Media Code Along! - + Webcam Fun -- Get User Media Code Along! -
          -
          - - -
          - - - -
          -
          - - - - + diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index 00355f5a9c..47c6d886d2 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -1,5 +1,71 @@ -const video = document.querySelector('.player'); -const canvas = document.querySelector('.photo'); + +/* DOM NODES */ +const video = document.querySelector('.video'); +console.log('video: ', video); + +const canvas = document.querySelector('.canvas'); +console.log('canvas: ', canvas); + const ctx = canvas.getContext('2d'); +console.log('ctx: ', ctx); + const strip = document.querySelector('.strip'); +console.log('strip: ', strip); + const snap = document.querySelector('.snap'); +console.log('snap: ', snap); + + +/* FUNCTIONS */ +const myConstraints = {audio: true, video: { + // width: { min: 1024, ideal: 1280, max: 1920 }, + // height: { min: 776, ideal: 720, max: 1080 }, + facingMode: "user" + }}; + +function getVideo() { + console.log('START getVideo'); + navigator.mediaDevices.getUserMedia(myConstraints) + .then(function(mediaStream) { + /* use the stream */ + console.log('mediaStream: ', mediaStream); + /* method 1 */ + video.src = window.URL.createObjectURL(mediaStream); + video.play(); + /* method 2 */ + // video.srcObject = mediaStream; + // video.onloadedmetadata = function(e) { + // video.play(); + // }; + }) + .catch(function(err) { + /* handle the error */ + console.error('err: ', err); + // console.log(err.name + ": " + err.message); // always check for errors at the end. + }); +} +// getVideo(); + +function videoToCanvas() { + console.log('START videoToCanvas'); + const w = video.videoWidth; + const h = video.videoHeight; + console.log(w,h); +} +videoToCanvas(); + +function takePhoto() { + alert('I JUST TOOK YOUR PHOTO'); +} + +function startStream() { + mediaStream.active = true; +} + +function stopStream() { + mediaStream.active = false; +} + + +/* EVENT LISTENERS */ + diff --git a/19--Webcam_Fun/style.css b/19--Webcam_Fun/style.css index 4e8bee57c8..8ce772c3de 100755 --- a/19--Webcam_Fun/style.css +++ b/19--Webcam_Fun/style.css @@ -1,40 +1,71 @@ -html { - box-sizing: border-box; -} - *, *:before, *:after { - box-sizing: inherit; + box-sizing:border-box; + padding:0; + margin:0; } html { - font-size: 10px; + font-size:100%; + font-family:sans-serif; background:#ffc600; } + + .photobooth { - background:white; - max-width:150rem; - margin: 2rem auto; - border-radius:2px; + background-color:rgba(127, 127, 127, 0.5); + max-width:100vw; + margin:5rem auto; + box-shadow:0 0 1rem 0 rgba(0, 0, 0, 0.25); + position:relative; } /*clearfix*/ .photobooth:after { - content: ''; - display: block; - clear: both; + content:''; + display:block; + clear:both; +} + +.controls { + position:absolute; + top:0; + left:0; + bottom:auto; + right:0; + background-color:rgba(0, 0, 0, 0.5); + padding:0; + display: flex; + flex-direction: row; + justify-content:space-between; +} +.controls > * {float:left; display:inline-block; text-align:center; flex:1;} +.controls button {padding:0.5rem; margin:0 0.25rem 0 0;} +.controls table {width:100%;} +.controls input {width:auto;} +.controls label { + display:inline-block; width:3rem; text-align:right; background-color:black; color:white; } +.controls .rgb {flex:5;} +.controls .rControl {background-color:red;} +.controls .gControl {background-color:green;} +.controls .bControl {background-color:blue;} +.controls .snapshot {/*float:right;*/} -.photo { +.canvas { width:100%; float:left; + background-color:rgba(0, 255, 0, 0.5); } -.player { - position: absolute; - top:20px; - right: 20px; +.video { + position:absolute; + bottom:1rem; + right:1rem; width:200px; + background-color:rgba(0, 0, 255, 0.5); + box-shadow:0 0.5rem 1.5rem 0 rgba(0, 0, 0, 0.5); + border:0.5rem white solid; } /* @@ -42,18 +73,23 @@ html { */ .strip { - padding:2rem; + padding:1rem; + background-color:rgba(255, 0, 0, 0.5); + position:absolute; + left:0; + bottom:0; + right:0; } .strip img { width:100px; - overflow-x: scroll; + overflow-x:scroll; padding:0.8rem 0.8rem 2.5rem 0.8rem; - box-shadow:0 0 3px rgba(0,0,0,0.2); + box-shadow:0 0.25rem 1rem 0 rgba(0, 0, 0, 0.25); background:white; } -.strip a:nth-child(5n+1) img { rotate: 10deg; } -.strip a:nth-child(5n+2) img { rotate: -2deg; } -.strip a:nth-child(5n+3) img { rotate: 8deg; } -.strip a:nth-child(5n+4) img { rotate: -11deg; } -.strip a:nth-child(5n+5) img { rotate: 12deg; } +.strip a:nth-child(5n+1) img { rotate:10deg; } +.strip a:nth-child(5n+2) img { rotate:-2deg; } +.strip a:nth-child(5n+3) img { rotate:8deg; } +.strip a:nth-child(5n+4) img { rotate:-11deg; } +.strip a:nth-child(5n+5) img { rotate:12deg; } diff --git a/index.html b/index.html index d8d227ae30..46bd702ccc 100755 --- a/index.html +++ b/index.html @@ -24,8 +24,8 @@
        • 15 - LocalStorage
        • 16 - Mouse Move Shadow
        • 17 - Sort Without Articles
        • - - +
        • 18 - Adding Up Times with Reduce
        • +
        • 19 - Webcam Fun
        • From 7460235a909d7fc889e464a9fa4d19e24f1cf9a6 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 12 Jan 2017 16:01:15 -0600 Subject: [PATCH 077/119] Project 19: make video print image to canvas. --- 19--Webcam_Fun/index-jds.html | 15 +++-- 19--Webcam_Fun/scripts.js | 114 +++++++++++++++++++++++----------- 19--Webcam_Fun/style.css | 33 +++++++--- 3 files changed, 113 insertions(+), 49 deletions(-) diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index 43bd0dab83..e79887417a 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -8,11 +8,13 @@
          -
          Camera +
          +
          -
          Experimental +
          + @@ -49,15 +51,18 @@
          Red
          -
          Photo - +
          + + +
          - +
          +
          diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index 47c6d886d2..208c31aca6 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -1,71 +1,115 @@ /* DOM NODES */ const video = document.querySelector('.video'); -console.log('video: ', video); - const canvas = document.querySelector('.canvas'); -console.log('canvas: ', canvas); - const ctx = canvas.getContext('2d'); -console.log('ctx: ', ctx); - const strip = document.querySelector('.strip'); -console.log('strip: ', strip); - const snap = document.querySelector('.snap'); -console.log('snap: ', snap); +/* VARIABLES */ +let myStream; +let front = true; +let positionX = 0; +let positionY = 0; /* FUNCTIONS */ -const myConstraints = {audio: true, video: { +const videoSettings = {audio: true, video: true}; + // { // width: { min: 1024, ideal: 1280, max: 1920 }, // height: { min: 776, ideal: 720, max: 1080 }, - facingMode: "user" - }}; + // facingMode: (front ? "user" : "environment") + // } -function getVideo() { +function getVideo(mode) { console.log('START getVideo'); - navigator.mediaDevices.getUserMedia(myConstraints) + navigator.mediaDevices.getUserMedia(videoSettings) .then(function(mediaStream) { - /* use the stream */ - console.log('mediaStream: ', mediaStream); - /* method 1 */ - video.src = window.URL.createObjectURL(mediaStream); - video.play(); - /* method 2 */ - // video.srcObject = mediaStream; - // video.onloadedmetadata = function(e) { - // video.play(); - // }; + myStream = mediaStream; + if (mode && mode === 'start') { + /* method 1 */ + video.src = window.URL.createObjectURL(myStream); + // video.play(); + /* method 2 */ + // video.srcObject = myStream; + video.onloadedmetadata = function(e) { + video.play(); + videoToCanvas(); + }; + } else { + video.src = ''; + // video.pause(); + } + console.log('myStream: ', myStream); }) .catch(function(err) { - /* handle the error */ console.error('err: ', err); // console.log(err.name + ": " + err.message); // always check for errors at the end. }); + // console.groupEnd(); } -// getVideo(); function videoToCanvas() { - console.log('START videoToCanvas'); - const w = video.videoWidth; - const h = video.videoHeight; - console.log(w,h); + console.group('START videoToCanvas'); + console.log(video); + + const vWidth = video.videoWidth; + const vHeight = video.videoHeight; + console.log(vWidth,vHeight); + + const wWidth = window.innerWidth; + const wHeight = window.innerHeight; + console.log(wWidth,wHeight); + + canvas.width = vWidth; + canvas.height = vHeight; + + // positionX = (wWidth - vWidth)/2; + // positionY = (wHeight - vHeight)/2; + + if (vWidth < wWidth && vHeight > wHeight) { + console.log('video taller than window'); + // stretch video vertically... + // canvas.width = vWidth; + // canvas.height = wHeight; + } else if (vWidth > wWidth && vHeight < wHeight) { + console.log('video wider than window'); + // stretch video horizontally... + // canvas.width = wWidth; + // canvas.height = vHeight; + } else { + console.log('video ??? than window'); + // canvas.width = vWidth; + // canvas.height = vHeight; + } + + // console.log(canvas.width,canvas.height); + setInterval(() => { + ctx.drawImage(video,positionX,positionY,vWidth,vHeight); + }, 100); + console.groupEnd(); +} + +function flipCamera() { + front = !front; + alert('I JUST FLIPPED YOUR CAMERA'); } -videoToCanvas(); function takePhoto() { alert('I JUST TOOK YOUR PHOTO'); } function startStream() { - mediaStream.active = true; + console.group('CAMERA ON'); + // myStream.active = true; + getVideo('start'); + console.groupEnd(); } function stopStream() { - mediaStream.active = false; + console.group('CAMERA OFF'); + // myStream.active = false; + getVideo('stop'); + console.groupEnd(); } - /* EVENT LISTENERS */ - diff --git a/19--Webcam_Fun/style.css b/19--Webcam_Fun/style.css index 8ce772c3de..f3980b0b87 100755 --- a/19--Webcam_Fun/style.css +++ b/19--Webcam_Fun/style.css @@ -10,14 +10,26 @@ html { background:#ffc600; } - +.controls {z-index: 2;} +.photobooth {z-index: 1;} +.strip {z-index: 3;} .photobooth { background-color:rgba(127, 127, 127, 0.5); - max-width:100vw; - margin:5rem auto; + + max-width:auto; + width:auto; + + max-height:100vh; + height:100%; + + margin:0 auto; box-shadow:0 0 1rem 0 rgba(0, 0, 0, 0.25); - position:relative; + position:absolute; + top:0; + left:0; + bottom:0; + right:0; } /*clearfix*/ @@ -34,6 +46,7 @@ html { bottom:auto; right:0; background-color:rgba(0, 0, 0, 0.5); + color:white; padding:0; display: flex; flex-direction: row; @@ -41,12 +54,12 @@ html { } .controls > * {float:left; display:inline-block; text-align:center; flex:1;} .controls button {padding:0.5rem; margin:0 0.25rem 0 0;} -.controls table {width:100%;} +.controls table {width:100%; margin-top: -0.5rem;} .controls input {width:auto;} .controls label { - display:inline-block; width:3rem; text-align:right; background-color:black; color:white; + display:inline-block; width:3rem; text-align:right; background-color:black; } -.controls .rgb {flex:5;} +.controls .rgb {flex:5; display: none;} .controls .rControl {background-color:red;} .controls .gControl {background-color:green;} .controls .bControl {background-color:blue;} @@ -54,7 +67,7 @@ html { .canvas { width:100%; - float:left; + height:auto; background-color:rgba(0, 255, 0, 0.5); } @@ -65,7 +78,7 @@ html { width:200px; background-color:rgba(0, 0, 255, 0.5); box-shadow:0 0.5rem 1.5rem 0 rgba(0, 0, 0, 0.5); - border:0.5rem white solid; + /*border:0.5rem white solid;*/ } /* @@ -74,8 +87,10 @@ html { .strip { padding:1rem; + height:auto; background-color:rgba(255, 0, 0, 0.5); position:absolute; + top:auto; left:0; bottom:0; right:0; From 34b55675e2b733426176606ca742c599f0d2320f Mon Sep 17 00:00:00 2001 From: Jeff S Date: Thu, 12 Jan 2017 16:53:45 -0600 Subject: [PATCH 078/119] minor clean up. --- 19--Webcam_Fun/scripts.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index 208c31aca6..bb19705720 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -13,15 +13,18 @@ let positionX = 0; let positionY = 0; /* FUNCTIONS */ -const videoSettings = {audio: true, video: true}; - // { - // width: { min: 1024, ideal: 1280, max: 1920 }, - // height: { min: 776, ideal: 720, max: 1080 }, - // facingMode: (front ? "user" : "environment") +const videoSettings = { + audio: false, + video: true + // video: { + // width: { min: 1024, ideal: 1280, max: 1920 }, + // height: { min: 776, ideal: 720, max: 1080 }, + // facingMode: (front ? "user" : "environment") // } +}; function getVideo(mode) { - console.log('START getVideo'); + console.group('START getVideo'); navigator.mediaDevices.getUserMedia(videoSettings) .then(function(mediaStream) { myStream = mediaStream; @@ -45,7 +48,7 @@ function getVideo(mode) { console.error('err: ', err); // console.log(err.name + ": " + err.message); // always check for errors at the end. }); - // console.groupEnd(); + console.groupEnd(); } function videoToCanvas() { @@ -89,15 +92,15 @@ function videoToCanvas() { console.groupEnd(); } +function takePhoto() { + alert('I JUST TOOK YOUR PHOTO'); +} + function flipCamera() { front = !front; alert('I JUST FLIPPED YOUR CAMERA'); } -function takePhoto() { - alert('I JUST TOOK YOUR PHOTO'); -} - function startStream() { console.group('CAMERA ON'); // myStream.active = true; From c4ce8d1410b150ae8f130f11dcbc5ef406538b71 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 13 Jan 2017 11:53:15 -0600 Subject: [PATCH 079/119] add a bunch of control buttons. --- 19--Webcam_Fun/index-jds.html | 4 +++- 19--Webcam_Fun/scripts.js | 34 +++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index e79887417a..e510a2d998 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -12,6 +12,7 @@ +
      @@ -54,7 +55,8 @@
      - + +
      diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index bb19705720..ed4f52deae 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -24,7 +24,7 @@ const videoSettings = { }; function getVideo(mode) { - console.group('START getVideo'); + console.group('START getVideo', mode); navigator.mediaDevices.getUserMedia(videoSettings) .then(function(mediaStream) { myStream = mediaStream; @@ -40,12 +40,11 @@ function getVideo(mode) { }; } else { video.src = ''; - // video.pause(); } console.log('myStream: ', myStream); }) .catch(function(err) { - console.error('err: ', err); + console.error('err: ', err.name); // console.log(err.name + ": " + err.message); // always check for errors at the end. }); console.groupEnd(); @@ -86,23 +85,40 @@ function videoToCanvas() { } // console.log(canvas.width,canvas.height); - setInterval(() => { + return setInterval(() => { ctx.drawImage(video,positionX,positionY,vWidth,vHeight); }, 100); console.groupEnd(); } -function takePhoto() { - alert('I JUST TOOK YOUR PHOTO'); +function snapPhoto() { + console.group('START snapPhoto'); + strip.innerHTML += ` + + `; + console.groupEnd(); +} + +function clearCanvas() { + console.group('START clearCanvas'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + console.groupEnd(); +} + +function clearStrip() { + console.group('START clearStrip'); + strip.innerHTML = ``; + console.groupEnd(); } function flipCamera() { + console.group('START flipCamera'); front = !front; - alert('I JUST FLIPPED YOUR CAMERA'); + console.groupEnd(); } function startStream() { - console.group('CAMERA ON'); + console.group('START startStream'); // myStream.active = true; getVideo('start'); console.groupEnd(); @@ -110,9 +126,9 @@ function startStream() { function stopStream() { console.group('CAMERA OFF'); - // myStream.active = false; getVideo('stop'); console.groupEnd(); } + /* EVENT LISTENERS */ From acd82baaafeaaa6f0ab4c021c1795236e051c85d Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 13 Jan 2017 14:01:48 -0600 Subject: [PATCH 080/119] work on the strip of snap shots. start video effects. --- 19--Webcam_Fun/index-jds.html | 7 +++- 19--Webcam_Fun/scripts.js | 64 ++++++++++++++++++++++++++++++++--- 19--Webcam_Fun/style.css | 46 ++++++++++++++++++------- 3 files changed, 98 insertions(+), 19 deletions(-) diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index e510a2d998..64e38d44bb 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -58,6 +58,11 @@
      +
      + +
      @@ -65,7 +70,7 @@
      -
      +
        diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index ed4f52deae..4f14eacaa8 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -4,6 +4,7 @@ const video = document.querySelector('.video'); const canvas = document.querySelector('.canvas'); const ctx = canvas.getContext('2d'); const strip = document.querySelector('.strip'); +const stripList = strip.querySelector('ul'); const snap = document.querySelector('.snap'); /* VARIABLES */ @@ -11,6 +12,9 @@ let myStream; let front = true; let positionX = 0; let positionY = 0; +let stripLen = 0; +const stripMax = 5; +const stripItemW = 150; /* FUNCTIONS */ const videoSettings = { @@ -36,11 +40,12 @@ function getVideo(mode) { // video.srcObject = myStream; video.onloadedmetadata = function(e) { video.play(); - videoToCanvas(); }; } else { video.src = ''; + myStream.active = false; } + console.log('video.src: ',video.src); console.log('myStream: ', myStream); }) .catch(function(err) { @@ -87,15 +92,43 @@ function videoToCanvas() { // console.log(canvas.width,canvas.height); return setInterval(() => { ctx.drawImage(video,positionX,positionY,vWidth,vHeight); + let pixels = ctx.getImageData(positionX,positionY,vWidth,vHeight); + console.log('pixels: ', pixels); + pixels = fxRed(pixels); + debugger; }, 100); console.groupEnd(); } function snapPhoto() { console.group('START snapPhoto'); - strip.innerHTML += ` - - `; + if (video.src !== '') { + // make snap sound + snap.currentTime = 0; + snap.play(); + + // take photo data from canvas + const item = document.createElement('li'); + item.style.width = stripItemW+'px'; + const data = canvas.toDataURL('image/jpeg'); + const link = document.createElement('a'); + link.href = data; + // link.download = 'picture'; + link.setAttribute('download','picture.jpg'); + link.innerHTML = `download picture`; + item.appendChild(link); + stripLen++; + stripList.insertBefore(item,stripList.firstChild); + console.log(item.clientHeight); + stripList.style.width = (stripLen*(stripItemW+0))+'px' + stripList.style.height = strip.style.height = item.clientHeight+40+'px'; + // if (stripLen < stripMax) { + // stripLen++; + // } else { + // stripLen = stripMax; + // stripList.removeChild(stripList.lastChild); + // } + } console.groupEnd(); } @@ -107,7 +140,7 @@ function clearCanvas() { function clearStrip() { console.group('START clearStrip'); - strip.innerHTML = ``; + stripList.innerHTML = ``; console.groupEnd(); } @@ -130,5 +163,26 @@ function stopStream() { console.groupEnd(); } +function fxRed(pixels) { + for (let i = 0; i < pixels.length; i+=4) { + // expression + pixels.data[i+0] = pixels.data[i+0]; // r + pixels.data[i+1] = 0; // g + pixels.data[i+2] = 0; // b + } +} +function fxGreen(pixels) { + for (let i = 1; i < pixels.length; i+=4) { + // expression + pixels[i] = ; // r + } +} +function fxBlue(pixels) { + for (let i = 2; i < pixels.length; i+=4) { + // expression + pixels[i] = ; // r + } +} /* EVENT LISTENERS */ +video.addEventListener('canplay',videoToCanvas); diff --git a/19--Webcam_Fun/style.css b/19--Webcam_Fun/style.css index f3980b0b87..85d14d8d87 100755 --- a/19--Webcam_Fun/style.css +++ b/19--Webcam_Fun/style.css @@ -55,11 +55,14 @@ html { .controls > * {float:left; display:inline-block; text-align:center; flex:1;} .controls button {padding:0.5rem; margin:0 0.25rem 0 0;} .controls table {width:100%; margin-top: -0.5rem;} -.controls input {width:auto;} +.controls input {width:auto;display:inline-block;} .controls label { display:inline-block; width:3rem; text-align:right; background-color:black; } -.controls .rgb {flex:5; display: none;} +.controls .rgb { + flex:4; + /*display: none;*/ +} .controls .rControl {background-color:red;} .controls .gControl {background-color:green;} .controls .bControl {background-color:blue;} @@ -73,7 +76,7 @@ html { .video { position:absolute; - bottom:1rem; + top:2rem; right:1rem; width:200px; background-color:rgba(0, 0, 255, 0.5); @@ -86,25 +89,42 @@ html { */ .strip { - padding:1rem; + width: 100%; height:auto; + margin:0; + padding:10px; background-color:rgba(255, 0, 0, 0.5); position:absolute; + overflow:auto; + overflow-x:scroll; + overflow-y:hidden; top:auto; left:0; bottom:0; right:0; } -.strip img { - width:100px; - overflow-x:scroll; - padding:0.8rem 0.8rem 2.5rem 0.8rem; +.strip ul { + text-indent:0; + list-style:none; + display:block; +} +.strip ul li { + text-indent:0; + list-style:none; + display:inline-block; +} +.strip ul li a { + width: 100%; +} +.strip ul li a img { + width:100%; + padding:5px 5px 20px 5px; box-shadow:0 0.25rem 1rem 0 rgba(0, 0, 0, 0.25); background:white; } -.strip a:nth-child(5n+1) img { rotate:10deg; } -.strip a:nth-child(5n+2) img { rotate:-2deg; } -.strip a:nth-child(5n+3) img { rotate:8deg; } -.strip a:nth-child(5n+4) img { rotate:-11deg; } -.strip a:nth-child(5n+5) img { rotate:12deg; } +.strip li:nth-child(5n+1) img { transform:rotate(4deg); } +.strip li:nth-child(5n+2) img { transform:rotate(-2deg); } +.strip li:nth-child(5n+3) img { transform:rotate(1deg); } +.strip li:nth-child(5n+4) img { transform:rotate(-3deg); } +.strip li:nth-child(5n+5) img { transform:rotate(2deg); } From 555f69c179b091ee6c51aee3f538c35cd1871511 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 13 Jan 2017 16:34:48 -0600 Subject: [PATCH 081/119] add chroma key functionality and other fx. --- 19--Webcam_Fun/index-jds.html | 20 ++++----- 19--Webcam_Fun/scripts.js | 85 ++++++++++++++++++++++++++--------- 19--Webcam_Fun/style.css | 46 ++++++++++++------- 3 files changed, 102 insertions(+), 49 deletions(-) diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index 64e38d44bb..1ef20ad418 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -17,37 +17,37 @@
        - +
        - + - + - +
        - + - + - +
        @@ -56,10 +56,10 @@ -
        -
        diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index 4f14eacaa8..b10d2e9b7c 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -61,17 +61,19 @@ function videoToCanvas() { const vWidth = video.videoWidth; const vHeight = video.videoHeight; - console.log(vWidth,vHeight); + console.log('vWidth:'+vWidth,'vHeight:'+vHeight); const wWidth = window.innerWidth; const wHeight = window.innerHeight; - console.log(wWidth,wHeight); + console.log('wWidth:'+wWidth,'wHeight:'+wHeight); - canvas.width = vWidth; - canvas.height = vHeight; + // set canvas to W&H of window + canvas.width = wWidth; + canvas.height = wHeight; - // positionX = (wWidth - vWidth)/2; - // positionY = (wHeight - vHeight)/2; + // center the canvas + positionX = (wWidth - vWidth)/2; + positionY = (wHeight - vHeight)/2; if (vWidth < wWidth && vHeight > wHeight) { console.log('video taller than window'); @@ -93,9 +95,21 @@ function videoToCanvas() { return setInterval(() => { ctx.drawImage(video,positionX,positionY,vWidth,vHeight); let pixels = ctx.getImageData(positionX,positionY,vWidth,vHeight); - console.log('pixels: ', pixels); - pixels = fxRed(pixels); - debugger; + + // manipulate pixels + pixels = fxChromaKey(pixels); + // pixels = fxSplit(pixels); + // pixels = fxRGB(pixels,'blue'); + + // control ghosting effect + ctx.globalAlpha = 0.5; + + // put pixels back + ctx.putImageData(pixels,positionX,positionY); + + // console.log('pixels: ', pixels); + // debugger; + }, 100); console.groupEnd(); } @@ -163,25 +177,52 @@ function stopStream() { console.groupEnd(); } -function fxRed(pixels) { - for (let i = 0; i < pixels.length; i+=4) { - // expression - pixels.data[i+0] = pixels.data[i+0]; // r - pixels.data[i+1] = 0; // g - pixels.data[i+2] = 0; // b +function fxChromaKey(pixels) { + const levels = {}; + document.querySelectorAll('.rgb input').forEach((input) => { + levels[input.name] = input.value; + }); + // console.log(levels); + // debugger; + for (let i = 0; i < pixels.data.length; i+=4) { + // put values into vars + red = pixels.data[i+0]; // r + green = pixels.data[i+1]; // g + blue = pixels.data[i+2]; // b + alpha = pixels.data[i+3]; // a + + // check if values are within ranges + if (red >= levels.rmin + && red <= levels.rmax + && green >= levels.gmin + && green <= levels.gmax + && blue >= levels.bmin + && blue <= levels.bmax) { + // take it out! + pixels.data[i + 3] = 0; + } } + return pixels; } -function fxGreen(pixels) { - for (let i = 1; i < pixels.length; i+=4) { + +function fxSplit(pixels) { + for (let i = 0; i < pixels.data.length; i+=4) { // expression - pixels[i] = ; // r + pixels.data[i-300] = pixels.data[i+0]; // r + pixels.data[i+300] = pixels.data[i+1]; // g + pixels.data[i+150] = pixels.data[i+2]; // b } + return pixels; } -function fxBlue(pixels) { - for (let i = 2; i < pixels.length; i+=4) { - // expression - pixels[i] = ; // r + +function fxRGB(pixels,effect) { + console.log('START fxRGB',effect); + for (let i = 0; i < pixels.data.length; i+=4) { + pixels.data[i+0] += (effect==='red') ? 150 : -50; // r + pixels.data[i+1] += (effect==='green') ? 150 : -50; // g + pixels.data[i+2] += (effect==='blue') ? 150 : -50; // b } + return pixels; } /* EVENT LISTENERS */ diff --git a/19--Webcam_Fun/style.css b/19--Webcam_Fun/style.css index 85d14d8d87..ded83d8207 100755 --- a/19--Webcam_Fun/style.css +++ b/19--Webcam_Fun/style.css @@ -1,21 +1,26 @@ +html { + font-size:100%; + font-family:sans-serif; + background:#ffc600; +} + *, *:before, *:after { box-sizing:border-box; padding:0; margin:0; + font-size:1rem; } -html { - font-size:100%; - font-family:sans-serif; - background:#ffc600; -} +body {} +fieldset {border:none;} .controls {z-index: 2;} .photobooth {z-index: 1;} .strip {z-index: 3;} .photobooth { - background-color:rgba(127, 127, 127, 0.5); + /* background-color:rgba(127, 127, 127, 0.5); */ + background:white; max-width:auto; width:auto; @@ -40,28 +45,32 @@ html { } .controls { + color: white; position:absolute; top:0; left:0; bottom:auto; right:0; - background-color:rgba(0, 0, 0, 0.5); + /* background-color:rgba(0, 0, 0, 0.5); */ + background:transparent; color:white; padding:0; display: flex; flex-direction: row; justify-content:space-between; + flex-wrap:nowrap; } -.controls > * {float:left; display:inline-block; text-align:center; flex:1;} +.controls > * {float:left; display:inline-block; text-align:center; flex:1; flex-wrap:nowrap;} .controls button {padding:0.5rem; margin:0 0.25rem 0 0;} -.controls table {width:100%; margin-top: -0.5rem;} -.controls input {width:auto;display:inline-block;} +.controls table {width:100%;} +.controls input {width:auto;display:inline-block; color:black;} +/* .controls input[type=range]:before {content:"Range";} */ .controls label { - display:inline-block; width:3rem; text-align:right; background-color:black; + display:inline-block; text-align:right; background-color:black; } .controls .rgb { - flex:4; - /*display: none;*/ + flex:3; + /* display: none; */ } .controls .rControl {background-color:red;} .controls .gControl {background-color:green;} @@ -71,15 +80,17 @@ html { .canvas { width:100%; height:auto; - background-color:rgba(0, 255, 0, 0.5); + /* background-color:rgba(0, 255, 0, 0.5); */ + background:transparent; } .video { position:absolute; - top:2rem; + top:4rem; right:1rem; width:200px; - background-color:rgba(0, 0, 255, 0.5); + /* background-color:rgba(0, 0, 255, 0.5); */ + background:black; box-shadow:0 0.5rem 1.5rem 0 rgba(0, 0, 0, 0.5); /*border:0.5rem white solid;*/ } @@ -93,7 +104,8 @@ html { height:auto; margin:0; padding:10px; - background-color:rgba(255, 0, 0, 0.5); + /* background-color:rgba(255, 0, 0, 0.5); */ + background:transparent; position:absolute; overflow:auto; overflow-x:scroll; From 4cdc656cc7ec0597f3858156577b7b7f2f0f9999 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 16 Jan 2017 11:12:04 -0600 Subject: [PATCH 082/119] break CSS out into files. put special effects scripts into own file. --- 19--Webcam_Fun/controls.css | 45 ++++++++++++ 19--Webcam_Fun/fx.js | 47 ++++++++++++ 19--Webcam_Fun/index-jds.html | 46 +++++++----- 19--Webcam_Fun/scripts.js | 109 ++++++++-------------------- 19--Webcam_Fun/strip.css | 39 ++++++++++ 19--Webcam_Fun/style.css | 133 +++++++++------------------------- 6 files changed, 226 insertions(+), 193 deletions(-) create mode 100644 19--Webcam_Fun/controls.css create mode 100644 19--Webcam_Fun/fx.js create mode 100644 19--Webcam_Fun/strip.css diff --git a/19--Webcam_Fun/controls.css b/19--Webcam_Fun/controls.css new file mode 100644 index 0000000000..e13da62083 --- /dev/null +++ b/19--Webcam_Fun/controls.css @@ -0,0 +1,45 @@ +/* container for video controls */ +.controls { + color:white; + position:absolute; + top:auto; + left:0; + bottom:0; + right:0; + background-color:rgba(0, 0, 0, 0.5); + /* background:transparent; */ + color:white; + /* padding:0; */ + display:flex; + flex-wrap:nowrap; + flex-direction:row; + justify-content:space-between; + align-items:center; +} +.controls > * { + /* float:left; */ + /* display:inline-block; */ + text-align:center; + flex:1; + flex-wrap:nowrap; + padding:0.5rem; +} + +.controls button {padding:0.5rem; margin:0 0.25rem 0 0;} +.controls table {width:100%;} +.controls input {width:auto; color:black;} +/* .controls input[type=range]:before {content:"Range";} */ +.controls label { + /* display:inline-block; */ + text-align:right; +} + +.controls .ctrl_camera {flex:2;} +.controls .ctrl_rgb {flex:3;} +.controls .ctrl_canvas {flex:1;} +.controls .ctrl_strip {flex:1;} + +.controls .rControl {background-color:red;} +.controls .gControl {background-color:green;} +.controls .bControl {background-color:blue;} +.controls .snapshot {/*float:right;*/} diff --git a/19--Webcam_Fun/fx.js b/19--Webcam_Fun/fx.js new file mode 100644 index 0000000000..432b386a91 --- /dev/null +++ b/19--Webcam_Fun/fx.js @@ -0,0 +1,47 @@ +function fxChromaKey(pixels) { + const levels = {}; + document.querySelectorAll('.rgb input').forEach((input) => { + levels[input.name] = input.value; + }); + // console.log(levels); + // debugger; + for (let i = 0; i < pixels.data.length; i+=4) { + // put values into vars + red = pixels.data[i+0]; // r + green = pixels.data[i+1]; // g + blue = pixels.data[i+2]; // b + alpha = pixels.data[i+3]; // a + + // check if values are within ranges + if (red >= levels.rmin + && red <= levels.rmax + && green >= levels.gmin + && green <= levels.gmax + && blue >= levels.bmin + && blue <= levels.bmax) { + // take it out! + pixels.data[i + 3] = 0; + } + } + return pixels; +} + +function fxSplit(pixels) { + for (let i = 0; i < pixels.data.length; i+=4) { + // expression + pixels.data[i-300] = pixels.data[i+0]; // r + pixels.data[i+300] = pixels.data[i+1]; // g + pixels.data[i+150] = pixels.data[i+2]; // b + } + return pixels; +} + +function fxRGB(pixels,effect) { + console.log('START fxRGB',effect); + for (let i = 0; i < pixels.data.length; i+=4) { + pixels.data[i+0] += (effect==='red') ? 150 : -50; // r + pixels.data[i+1] += (effect==='green') ? 150 : -50; // g + pixels.data[i+2] += (effect==='blue') ? 150 : -50; // b + } + return pixels; +} diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index 1ef20ad418..3a52f7d054 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -4,18 +4,27 @@ Webcam Fun -- Get User Media Code Along! + + +
        +

        webcam fun

        +
        + +
        +
        -
        + +
        - - - + + +
        -
        - +
        + Experimental - + -
        - -
        +
        + booth + + + +
        +
        + strip + + +
        +
        + fx: + +
        Experimental
        - - - - - - -
        - - + + - - + + - - + +
        - - + + - - + + - - + +
        -
        - - - -
        -
        - - -
        @@ -81,7 +95,7 @@

        webcam fun

        -
        + diff --git a/19--Webcam_Fun/scripts.js b/19--Webcam_Fun/scripts.js index 2a2c0fc363..360f55df14 100644 --- a/19--Webcam_Fun/scripts.js +++ b/19--Webcam_Fun/scripts.js @@ -1,11 +1,14 @@ +/* scripts.js */ /* DOM NODES */ const video = document.querySelector('.video'); const canvas = document.querySelector('.canvas'); const ctx = canvas.getContext('2d'); const strip = document.querySelector('.strip'); -const stripList = strip.querySelector('ul'); const snap = document.querySelector('.snap'); +const fxSelect = document.querySelector('#fx'); +const inputs = document.querySelectorAll('.ctrl_fx') +const inputLimit = document.querySelector('#limit'); /* VARIABLES */ let myStream; @@ -13,9 +16,12 @@ let front = true; let positionX = 0; let positionY = 0; let stripLen = 0; +let stripLimit = true; const stripMax = 5; const stripItemW = 150; +inputLimit.checked = stripLimit; + /* FUNCTIONS */ const videoSettings = { audio: false, @@ -53,60 +59,100 @@ function getVideo(mode) { function videoToCanvas() { console.group('START videoToCanvas'); - console.log(video); + // console.log(video); const vWidth = video.videoWidth; const vHeight = video.videoHeight; - console.log('vWidth:'+vWidth,'vHeight:'+vHeight); + // console.log('vWidth:'+vWidth,'vHeight:'+vHeight); + + const ratio = vWidth/vHeight; + // console.log('ratio: ', ratio); const wWidth = window.innerWidth; const wHeight = window.innerHeight; - console.log('wWidth:'+wWidth,'wHeight:'+wHeight); + // console.log('wWidth:'+wWidth,'wHeight:'+wHeight); /* set canvas to W&H of window */ - canvas.width = wWidth; - canvas.height = wHeight; + // canvas.width = wWidth; + // canvas.height = wHeight; /* center the canvas */ // positionX = (wWidth - vWidth)/2; // positionY = (wHeight - vHeight)/2; - if (vWidth < wWidth && vHeight > wHeight) { - console.log('video taller than window'); - // stretch video vertically... + // if (vWidth < wWidth && vHeight > wHeight) { + // console.log('video taller than window'); + // // stretch video vertically... + // canvas.width = vWidth; + // canvas.height = wHeight; + // } else if (vWidth > wWidth && vHeight < wHeight) { + // console.log('video wider than window'); + // // stretch video horizontally... + // canvas.width = wWidth; + // canvas.height = vHeight; + // } else { + // console.log('video ??? than window'); canvas.width = vWidth; - canvas.height = wHeight; - } else if (vWidth > wWidth && vHeight < wHeight) { - console.log('video wider than window'); - // stretch video horizontally... - canvas.width = wWidth; canvas.height = vHeight; + // } + + const randoms = []; + randoms.push(Math.floor(Math.random()*100)); + randoms.push(Math.floor(Math.random()*100)); + randoms.push(Math.floor(Math.random()*100)); + console.log('randoms: ', randoms); + + console.log(fxSelect.value); + if (fxSelect.value = 'chroma') { + for (var i = 0; i < inputs.length; i++) { + // console.log('input: ',inputs[i]); + inputs[i].readOnly = false; + } } else { - console.log('video ??? than window'); - canvas.width = vWidth; - canvas.height = vHeight; + for (var i = 0; i < inputs.length; i++) { + // console.log('input: ',inputs[i]); + inputs[i].readOnly = true; + } } // console.log(canvas.width,canvas.height); - return setInterval(() => { - ctx.drawImage(video,positionX,positionY,vWidth,vHeight); - let pixels = ctx.getImageData(positionX,positionY,vWidth,vHeight); - - /* manipulate pixels */ - pixels = fxChromaKey(pixels); - // pixels = fxSplit(pixels); - // pixels = fxRGB(pixels,'blue'); - - /* control ghosting effect */ - ctx.globalAlpha = 0.5; - - /* put pixels back */ - ctx.putImageData(pixels,positionX,positionY); - - // console.log('pixels: ', pixels); - // debugger; - + function videoFX (fx) { + ctx.drawImage(video,positionX,positionY,vWidth,vHeight); + let pixels = ctx.getImageData(positionX,positionY,vWidth,vHeight); + + /* manipulate pixels */ + switch(fx) { + case 'chroma': + pixels = fxChromaKey(pixels); + break; + case 'split': + pixels = fxSplit(pixels,randoms); + break; + case 'r_channel': + pixels = fxRGB(pixels,'red'); + break; + case 'g_channel': + pixels = fxRGB(pixels,'green'); + break; + case 'b_channel': + pixels = fxRGB(pixels,'blue'); + break; + } + + /* control ghosting effect */ + // ctx.globalAlpha = 0.5; + + /* put pixels back */ + ctx.putImageData(pixels,positionX,positionY); + + // console.log('pixels: ', pixels); + // debugger; + + } + const videoInterval = setInterval(()=>{ + videoFX(fxSelect.value); }, 100); + return videoInterval console.groupEnd(); } @@ -118,32 +164,33 @@ function snapPhoto() { snap.play(); /* take photo data from canvas */ - // const item = document.createElement('li'); - // item.style.width = stripItemW+'px'; const data = canvas.toDataURL('image/jpeg'); const link = document.createElement('a'); link.href = data; link.setAttribute('download','picture.jpg'); link.innerHTML = `download picture`; link.style.width = stripItemW+'px'; - // item.appendChild(link); console.log('link',link); /* put photo snaps into strip */ - stripLen++; - strip.insertBefore(link,strip.firstChild); - // strip.insertBefore(item,strip.firstChild); - // console.log(item.clientHeight); - // strip.style.height = (stripLen*(stripItemW+0))+'px' - // strip.style.width = strip.style.height = link.clientHeight+40+'px'; - + // stripLen++; /* set a max limit on number of photo snaps */ - // if (stripLen < stripMax) { - // stripLen++; - // } else { - // stripLen = stripMax; - // strip.removeChild(strip.lastChild); - // } + // stripLimit = true; + if (stripLimit && (stripLen < stripMax)) { + console.log('NO LIMIT'); + stripLen++; + } else { + console.log('YES LIMIT'); + stripLen = stripMax; + strip.removeChild(strip.lastChild); + } + console.log('stripLen: ', stripLen); + + if (stripLen>0) { + strip.style.display = 'flex'; + } + strip.insertBefore(link,strip.firstChild); + strip.style.width = stripItemW+20+'px' } console.groupEnd(); @@ -182,3 +229,6 @@ function stopStream() { /* EVENT LISTENERS */ video.addEventListener('canplay',videoToCanvas); +inputLimit.addEventListener('click',(e)=>{ + console.log(e.target.checked); +}) \ No newline at end of file diff --git a/19--Webcam_Fun/strip.css b/19--Webcam_Fun/strip.css index dc265fa991..8149efbcac 100644 --- a/19--Webcam_Fun/strip.css +++ b/19--Webcam_Fun/strip.css @@ -1,21 +1,21 @@ /* photobooth picture strip */ .strip { - width:100%; - height:auto; + width:200px; + height:100%; margin:0; - padding:1rem; - /* background-color:rgba(255, 0, 0, 0.5); */ - background:transparent; + padding:1rem 10px; + /* background:transparent; */ + background-color:rgba(0, 0, 0, 0.5); position:absolute; overflow:auto; overflow-x:hidden; overflow-y:auto; top:0; - left:0; + left:1rem; bottom:0; right:auto; - display:flex; + display:none; flex-wrap:nowrap; flex-direction:column; justify-content:start; diff --git a/19--Webcam_Fun/style.css b/19--Webcam_Fun/style.css index 4c7d91a7e2..5ecd7febae 100755 --- a/19--Webcam_Fun/style.css +++ b/19--Webcam_Fun/style.css @@ -1,4 +1,6 @@ -*, *:before, *:after { +*, +*:before, +*:after { box-sizing:border-box; padding:0; margin:0; @@ -11,63 +13,94 @@ html { body { font-size:1rem; - background-color:rgb(255, 0, 255); - /* background:black; */ + background:black; padding:0; margin:0; } -table {border-collapse: collapse;} -fieldset {border:none;} - -/* Z-INDICES FOR LAYERING */ -.controls {z-index:3;} -.photobooth {z-index:1;} -.strip {z-index:2;} +h1, +h2, +h3, +h4, +h5, +h6 {color:black;} -/* container for webcam video and canvas */ -.photobooth { - background:white; - background-color:rgba(255, 255, 0, 0.5); +table { + width:100%; + /* border-collapse:separate; */ + border-collapse:collapse; + border-width:3px; +} - /* max-width:auto; */ +legend, +label, +input, +button, +select, +td { + font-size:0.9em; + color:black; + width:auto; + white-space:nowrap; +} +td {margin: 0 0.25rem 0.25rem 0;} +legend, +label, +input, +button, +select { + display: inline-block; + border-width:3px; + padding:0.25rem 0.5rem; + line-height: 1.5; +} +td > legend, +td > label, +td > input, +td > button, +td > select, +fieldset {border:none;} +label, +input, +button, +select { + border-style: solid; + border-color:rgba(255,255,255,0.5) rgba(153,153,153,0.5) rgba(102,102,102,0.5) rgba(204,204,204,0.5); + /* border-color:yellow limegreen cyan magenta; */ + border-radius:0.25rem; + /* width:100%; */ /* width:auto; */ - - /* max-height:100vh; */ - /* height:100%; */ - - /* box-shadow:0 0 1rem 0 rgba(0, 0, 0, 0.25); */ - position:absolute; - top:0; - left:0; - bottom:0; - right:0; + /* display:inline-block; */ } - -/*clearfix*/ -.photobooth:after { - content:''; - display:block; - clear:both; +button+button, +button+input, +input+button, +input+input, +label+label, +label+input, +input+label, +label+button, +button+label {margin-top:0.25rem;} +label { + /* width:40%; */ + /* color:white; */ + /* text-align:right; */ + padding-left:0; } - -.canvas { +button { width:100%; - height:auto; - background:transparent; - background-color:rgba(0, 255, 0, 0.5); + /* padding:0.5rem; */ + /* margin:0 0 0.25rem 0; */ } +input[type=checkbox], +input[type=radio] {margin:0 0.25rem 0 0.5rem;} +/* Z-INDICES FOR LAYERING */ +header {z-index:1;display:none;} +main {z-index:2;} -.video { - background:black; - background:white; - padding:5px; - position:absolute; - top:2rem; - right:2rem; - width:200px; - box-shadow:0 0.5rem 1.5rem 0 rgba(0, 0, 0, 0.5); -} +.controls {z-index:30;} +.photobooth {z-index:10;} +.strip {z-index:20;} /* misc classes */ .status {background-color:palegoldenrod;} diff --git a/19--Webcam_Fun/test.css b/19--Webcam_Fun/test.css new file mode 100644 index 0000000000..30df0f6f93 --- /dev/null +++ b/19--Webcam_Fun/test.css @@ -0,0 +1,6 @@ +body {background-color:rgba(255, 0, 0, 0.5);} +.strip {background-color:rgba(0, 255, 0, 0.5);} +.controls {background-color:rgba(0, 0, 255, 0.5);} +.photobooth {background-color:rgba(255, 255, 0, 0.5);} +.canvas {background-color:rgba(255, 0, 255, 0.5);} +.video {background-color:rgba(0, 255, 255, 0.5);} From 2bd63050e63027310b9da8353072fa3f33eca553 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Mon, 16 Jan 2017 17:04:29 -0600 Subject: [PATCH 084/119] controls show/hide based on availability. --- 19--Webcam_Fun/fx.js | 53 ++++++---- 19--Webcam_Fun/index-jds.html | 21 +++- 19--Webcam_Fun/scripts.js | 188 ++++++++++++++++++++++++---------- 3 files changed, 183 insertions(+), 79 deletions(-) diff --git a/19--Webcam_Fun/fx.js b/19--Webcam_Fun/fx.js index 15374936e8..5c9d715910 100644 --- a/19--Webcam_Fun/fx.js +++ b/19--Webcam_Fun/fx.js @@ -1,17 +1,18 @@ /* fx.js */ -function fxChromaKey(pixels) { +function fxChromaKey(data) { + // console.log('START fxChromaKey'); const levels = {}; - document.querySelectorAll('.rgb input').forEach((input) => { + document.querySelectorAll('#ctrl_fx--chroma input').forEach((input) => { levels[input.name] = input.value; }); // console.log(levels); // debugger; - for (let i = 0; i < pixels.data.length; i+=4) { + for (let i = 0; i < data.data.length; i+=4) { // put values into vars - red = pixels.data[i+0]; // r - green = pixels.data[i+1]; // g - blue = pixels.data[i+2]; // b - alpha = pixels.data[i+3]; // a + red = data.data[i+0]; // r + green = data.data[i+1]; // g + blue = data.data[i+2]; // b + alpha = data.data[i+3]; // a // check if values are within ranges if (red >= levels.rmin @@ -21,27 +22,35 @@ function fxChromaKey(pixels) { && blue >= levels.bmin && blue <= levels.bmax) { // take it out! - pixels.data[i + 3] = 0; + data.data[i + 3] = 0; } } - return pixels; + return data; } -function fxSplit(pixels,randoms) { - for (let i = 0; i < pixels.data.length; i+=4) { - pixels.data[i-randoms[1]] = pixels.data[i+0]; // r - pixels.data[i+randoms[2]] = pixels.data[i+1]; // g - pixels.data[i+randoms[3]] = pixels.data[i+2]; // b +function fxSplit(data,nums) { + // console.log('START fxSplit'); + for (let i = 0; i < data.data.length; i+=4) { + data.data[i+nums[1]] = data.data[i+0]; // r + data.data[i+nums[2]] = data.data[i+1]; // g + data.data[i+nums[3]] = data.data[i+2]; // b } - return pixels; + return data; } -function fxRGB(pixels,effect) { - console.log('START fxRGB',effect); - for (let i = 0; i < pixels.data.length; i+=4) { - pixels.data[i+0] += (effect==='red') ? 150 : -50; // r - pixels.data[i+1] += (effect==='green') ? 150 : -50; // g - pixels.data[i+2] += (effect==='blue') ? 150 : -50; // b +function fxRGB(data,effect) { + // console.log('START fxRGB',effect); + for (let i = 0; i < data.data.length; i+=4) { + data.data[i+0] += (effect==='red') ? 150 : -50; // r + data.data[i+1] += (effect==='green') ? 150 : -50; // g + data.data[i+2] += (effect==='blue') ? 150 : -50; // b } - return pixels; + return data; +} + +function fxPixelate(data,resolution) { + // console.log('START fxPixelate',resolution); + for (let i = 0; i < data.data.length; i+=4) { + } + return data; } diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index 41277ef11e..0d16fd2ce5 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -26,7 +26,7 @@

        webcam fun

        booth - +
        @@ -49,7 +49,24 @@

        webcam fun

        - +
        + + + + + + +
        + +
        + @@ -189,12 +194,27 @@

        webcam fun

        + + + + + + + +
        + +
        snaps 0 - @@ -216,7 +236,7 @@

        webcam fun

        - + diff --git a/19--Webcam_Fun/js/fx.js b/19--Webcam_Fun/js/fx.js index 8c9524060b..f51edd6afe 100644 --- a/19--Webcam_Fun/js/fx.js +++ b/19--Webcam_Fun/js/fx.js @@ -4,7 +4,7 @@ console.log('fx.js READY!'); * check if each pixel's color value falls within ranges set * by inputs. if it does, drop alpha value to 0 to hide pixel. * @param {big array} data - The pixels. - * @return {big array} The modified pixels. + * @return {big array} - The modified pixels. */ function fFxChromaKey(uint8) { // console.log('START fFxChromaKey'); @@ -43,7 +43,7 @@ function fFxChromaKey(uint8) { * distinctly separate layers. * @param {big array} data - The pixels. * @param {array} nums - Integers used to shift each R, G, and B value. - * @return {big array} The modified pixels. + * @return {big array} - The modified pixels. */ function fFxChannelSplit(uint8,nums) { // console.log('START fFxChannelSplit'); @@ -60,7 +60,7 @@ function fFxChannelSplit(uint8,nums) { * create a monochromatic picture. * @param {big array} data - The pixels. * @param {array} nums - Integers used to shift each R, G, and B value. - * @return {big array} The modified pixels. + * @return {big array} - The modified pixels. */ function fFxColorize(uint8,nums) { // console.log('START fFxRGB',nums); @@ -72,24 +72,11 @@ function fFxColorize(uint8,nums) { return uint8; } -/** - * [fFxPixelate description] - * @param {big array} data - The pixels. - * @param {number} res - Resolution of the pixels: 1 = 1:1, 2 = 1:2, 3 = 1:3, etc. - * @return {big array} The modified pixels. - */ -function fFxPixelate(uint8,res) { - // console.log('START fFxPixelate',res); - for (let i = 0; i < uint8.data.length; i+=4) { - } - return uint8; -} - /** * [fFxSaturate description] * @param {big array} data - The pixels. * @param {number} saturation - How saturated the video should be: 0 = monochrome, 100 = normal color, 200 = super color. - * @return {big array} The modified pixels. + * @return {big array} - The modified pixels. */ function fFxSaturate(uint8,nums) { // console.log('START fFxSaturate',nums); @@ -103,3 +90,53 @@ function fFxSaturate(uint8,nums) { } return uint8; } + +/** + * [invert description] + * @return {[type]} [description] + */ +function fFxInvert (uint8) { + for (var i = 0; i < uint8.data.length; i += 4) { + uint8.data[i+0] = 255 - uint8.data[i+0]; // red + uint8.data[i+1] = 255 - uint8.data[i+1]; // green + uint8.data[i+2] = 255 - uint8.data[i+2]; // blue + } + return uint8; +}; + + +/** + * [fFxPixelate description] + * @param {big array} data - The pixels. + * @param {number} res - Resolution of the pixels: 1 = 1:1, 2 = 1:2, 3 = 1:3, etc. + * @return {big array} - The modified pixels. + */ +function fFxPixelate(uint8,res) { + // console.log('START fFxPixelate',res); + /* Uint8ClampedArray */ + console.dir(uint8); + console.dir(uint8.data); + // console.log('uint8.data.length: ',uint8.data.length); + // console.log('uint8.width: ',uint8.width); + let compressed = []; + for (let i = 0; i < uint8.data.length; i+=4) { + if ( ((i/4) % res) === 0 ) { + // console.log('slicing'); + compressed.push(uint8.data[i+0]); + compressed.push(uint8.data[i+1]); + compressed.push(uint8.data[i+2]); + compressed.push(uint8.data[i+3]); + } else { + // console.log('NOT slicing'); + } + } + console.log('compressed.length: ',compressed.length); + console.log('compressed.length/4: ',compressed.length/4); + debugger; + // console.dir(Uint8ClampedArray.from(compressed)); + // uint8.data = new Uint8ClampedArray(compressed); + compressed = Uint8ClampedArray.from(compressed); + // console.dir(compressed); + let newImageData = new ImageData(compressed, (uint8.width/res), (uint8.height/res)); + return newImageData; +} diff --git a/19--Webcam_Fun/js/mirror.js b/19--Webcam_Fun/js/mirror.js index ab2dc44368..13602b84a6 100644 --- a/19--Webcam_Fun/js/mirror.js +++ b/19--Webcam_Fun/js/mirror.js @@ -1,10 +1,10 @@ /** - * [fMirror description] + * [fMirrorOld description] * @param {big array} data - The pixels. * @return {big array} The modified pixels. */ -function fMirror(pixels) { - console.group('START fMirror'); +function fMirrorOld (pixels) { + console.group('START fMirrorOld'); // console.log('pixels:', pixels); @@ -54,7 +54,7 @@ pixels.data = arr; /** * The above results in an error: * Uncaught RangeError: Maximum call stack size exceeded - at fMirror (mirror.js:24) + at fMirrorOld (mirror.js:24) at videoFX (scripts.js:406) at setInterval (scripts.js:441) * Need different approach! diff --git a/19--Webcam_Fun/js/scripts.js b/19--Webcam_Fun/js/scripts.js index 310b7202cd..5cde40a714 100644 --- a/19--Webcam_Fun/js/scripts.js +++ b/19--Webcam_Fun/js/scripts.js @@ -71,6 +71,7 @@ let positionX = 0; let positionY = 0; let stripLen = 0; let videoInterval; +let canvasScale = 1; const stripMax = 5; const stripItemW = 140; const constraints = {audio: false, video: true}; @@ -123,7 +124,7 @@ function fChromaKeyInputs (group) { // e.target.parentElement.innerHTML = `${e.target.value}`; } }); - console.log('levels: ', levels); + // console.log('levels: ', levels); rgbMin.querySelector("input").style.backgroundColor = `rgb(${levels["rmin"]},${levels["gmin"]},${levels["bmin"]})`; rgbMax.querySelector("input").style.backgroundColor = `rgb(${levels["rmax"]},${levels["gmax"]},${levels["bmax"]})`; console.groupEnd(); @@ -153,7 +154,7 @@ function fUpdateInput (input) { bg = `#808080`; br = `${1/input.value}rem`; } else { - console.warn(' NOT saturate OR pixelate!'); + // console.warn(' NOT saturate OR pixelate!'); } label.querySelector("code").style.backgroundColor = bg; label.querySelector("code").style.borderRadius = br; @@ -169,10 +170,12 @@ inputAllRange.forEach((input)=>{ function fMirror () { if (mirror.checked) { // console.log('FLIP IT'); - canvas.style.transform = 'scale(-1,1)'; + canvas.style.transform = `scale(-${canvasScale},${canvasScale})`; + // canvas.style.transform = 'scale(-1,1)'; } else { // console.log('DON\'T FLIP IT'); - canvas.style.transform = 'scale(1,1)'; + canvas.style.transform = `scale(${canvasScale},${canvasScale})`; + // canvas.style.transform = 'scale(1,1)'; } } fMirror(); @@ -337,8 +340,6 @@ if (navigator.mediaDevices) { const wRatio = wWidth/wHeight; // console.log('wRatio: ', wRatio); - let canvasScale = 1; - function fCheckArea (a,b) { console.group('START fCheckArea'); let area; @@ -406,12 +407,14 @@ if (navigator.mediaDevices) { canvas.width = wWidth; canvas.height = wHeight; - if (mirror.checked) { - canvas.style.transform = `scale(-${canvasScale},${canvasScale})`; - } else { - canvas.style.transform = `scale(${canvasScale},${canvasScale})`; - } - console.log('canvas.style.transform: ',canvas.style.transform); + + fMirror(); + // if (mirror.checked) { + // canvas.style.transform = `scale(-${canvasScale},${canvasScale})`; + // } else { + // canvas.style.transform = `scale(${canvasScale},${canvasScale})`; + // } + // console.log('canvas.style.transform: ',canvas.style.transform); /* center the canvas */ positionX = (wWidth - vWidth)/2; @@ -471,51 +474,26 @@ if (navigator.mediaDevices) { console.groupEnd(); /* values for F/X function */ + console.group('inputPixelate.value: ', inputPixelate.value); const inputPixelateVal = parseInt(inputPixelate.value); console.group('inputPixelateVal: ', inputPixelateVal); - let intPixelate = 2; + let intPixelate = parseInt(inputPixelate.value); // console.log('intPixelate: ', intPixelate); console.groupEnd(); - // console.log('selectFx.value: ',selectFx.value); - // const effect = selectFx.value | ''; - // console.log('effect: ', effect); - // /* enable F/X controls */ - // if (effect === 'chroma') { - // console.log('toggle chroma controls'); - // // get initial value for effect - // } else if (effect === 'split') { - // console.log('toggle split controls'); - // // get initial value for effect - // // console.log('selectSplit: ', selectSplit.value); - // } else if (effect === 'colorize') { - // console.log('toggle colorize controls'); - // // get initial value for effect - // // console.log('selectColorize: ', selectColorize.value); - // } else { - // console.log('no effect chosen yet'); - // } - - // console.log(canvas.width,canvas.height); - - /** - * manipulate pixels with video effect. - * @param {[type]} fx [description] - * @return {[type]} [description] - */ + /** + * manipulate pixels with video effect. + * @param {[type]} fx [description] + * @return {[type]} [description] + */ function videoFX (fx) { // console.log('fx: ', fx); ctx.drawImage(video,positionX,positionY,vWidth,vHeight); let pixels = ctx.getImageData(positionX,positionY,vWidth,vHeight); - // console.log(pixels); + // console.log(pixels.data.length); // 1,228,800 (bits) // console.log(pixels.data.length/4); // 307,200 (pixels) - // if (mirror.checked) { - // // console.log('mirror.checked: ', mirror.checked); - // fMirror(pixels); - // } - /* manipulate pixels */ switch(fx) { case 'Colorize': @@ -533,6 +511,9 @@ if (navigator.mediaDevices) { case 'Pixelate': pixels = fFxPixelate(pixels,intPixelate); break; + case 'Invert': + // pixels = fFxInvert(pixels); + break; } /* control ghosting effect */ @@ -757,6 +738,6 @@ window.addEventListener('resize', fMediaQueries); /* fake UI clicks to open controls */ startStream(); -selectFx.selectedIndex = 1; +selectFx.selectedIndex = 5; toggleFxControls(); diff --git a/19--Webcam_Fun/js/utils.js b/19--Webcam_Fun/js/utils.js index f0ab4bb63f..8800056e42 100644 --- a/19--Webcam_Fun/js/utils.js +++ b/19--Webcam_Fun/js/utils.js @@ -1,6 +1,12 @@ /* utils.js */ console.log('utils.js READY!'); +if (!Uint8Array.prototype.slice) { + Object.defineProperty(Uint8Array.prototype, 'slice', { + value: Array.prototype.slice + }); +} + /* toggle button enable/disable */ function toggleButton(el,state) { // console.dir(el); From b073364e64d78ffefafe594c4e229887811928c2 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 3 Feb 2017 12:33:12 -0600 Subject: [PATCH 115/119] Proj 19: Figured out that I need to square the resolution in array len calc. Also that canvas positioning and CSS scaling adds many data to the image data array. The resulting effect is two tiny, squished images...which would be nice for stereoscopy if they were actually from two different angles.. --- 19--Webcam_Fun/css/theme.css | 3 +- 19--Webcam_Fun/index-jds.html | 30 ++------ 19--Webcam_Fun/js/fx.js | 133 +++++++++++++++++++--------------- 19--Webcam_Fun/js/scripts.js | 10 +-- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/19--Webcam_Fun/css/theme.css b/19--Webcam_Fun/css/theme.css index e24d1494a5..b0e16a3995 100644 --- a/19--Webcam_Fun/css/theme.css +++ b/19--Webcam_Fun/css/theme.css @@ -18,7 +18,8 @@ .ctrls legend .value, .ctrls label .value { border-radius:1rem; - color:rgb(51,51,51); + /* color:rgb(51,51,51); */ + color:rgb(255,255,255); background-color:rgb(204,204,204); /* box-shadow:0 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.5); */ } diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index 26da8bf275..b896a5503f 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -11,25 +11,20 @@ -

        webcam fun

        -
        -
        cam - -
        @@ -39,9 +34,9 @@

        webcam fun

        + - - - - @@ -185,13 +177,10 @@

        webcam fun

        - - -
        @@ -199,14 +188,11 @@

        webcam fun

        -
        @@ -221,23 +207,17 @@

        webcam fun

        -
        -
        - - - - diff --git a/19--Webcam_Fun/js/fx.js b/19--Webcam_Fun/js/fx.js index f51edd6afe..9f2d71e757 100644 --- a/19--Webcam_Fun/js/fx.js +++ b/19--Webcam_Fun/js/fx.js @@ -1,12 +1,17 @@ /* fx.js */ console.log('fx.js READY!'); + +/** + * Uint8ClampedArray + */ + /** * check if each pixel's color value falls within ranges set * by inputs. if it does, drop alpha value to 0 to hide pixel. * @param {big array} data - The pixels. * @return {big array} - The modified pixels. */ -function fFxChromaKey(uint8) { +function fFxChromaKey(array255) { // console.log('START fFxChromaKey'); // create empty array of min & max values const levels = {}; @@ -16,12 +21,12 @@ function fFxChromaKey(uint8) { }); // console.log(levels); // debugger; - for (let i = 0; i < uint8.data.length; i+=4) { + for (let i = 0; i < array255.data.length; i+=4) { // put values into vars - red = uint8.data[i+0]; // r - green = uint8.data[i+1]; // g - blue = uint8.data[i+2]; // b - alpha = uint8.data[i+3]; // a + red = array255.data[i+0]; // r + green = array255.data[i+1]; // g + blue = array255.data[i+2]; // b + alpha = array255.data[i+3]; // a // check if values are within ranges if (red >= levels.rmin @@ -31,10 +36,10 @@ function fFxChromaKey(uint8) { && blue >= levels.bmin && blue <= levels.bmax) { // take it out! - uint8.data[i + 3] = 0; + array255.data[i + 3] = 0; } } - return uint8; + return array255; } /** @@ -45,14 +50,14 @@ function fFxChromaKey(uint8) { * @param {array} nums - Integers used to shift each R, G, and B value. * @return {big array} - The modified pixels. */ -function fFxChannelSplit(uint8,nums) { +function fFxChannelSplit(array255,nums) { // console.log('START fFxChannelSplit'); - for (let i = 0; i < uint8.data.length; i+=4) { - uint8.data[i+nums[0]] = uint8.data[i+0]; // r - uint8.data[i+nums[1]] = uint8.data[i+1]; // g - uint8.data[i+nums[2]] = uint8.data[i+2]; // b + for (let i = 0; i < array255.data.length; i+=4) { + array255.data[i+nums[0]] = array255.data[i+0]; // r + array255.data[i+nums[1]] = array255.data[i+1]; // g + array255.data[i+nums[2]] = array255.data[i+2]; // b } - return uint8; + return array255; } /** @@ -62,14 +67,14 @@ function fFxChannelSplit(uint8,nums) { * @param {array} nums - Integers used to shift each R, G, and B value. * @return {big array} - The modified pixels. */ -function fFxColorize(uint8,nums) { +function fFxColorize(array255,nums) { // console.log('START fFxRGB',nums); - for (let i = 0; i < uint8.data.length; i+=4) { - uint8.data[i+0] += nums[0]; // r - uint8.data[i+1] += nums[1]; // g - uint8.data[i+2] += nums[2]; // b + for (let i = 0; i < array255.data.length; i+=4) { + array255.data[i+0] += nums[0]; // r + array255.data[i+1] += nums[1]; // g + array255.data[i+2] += nums[2]; // b } - return uint8; + return array255; } /** @@ -78,65 +83,79 @@ function fFxColorize(uint8,nums) { * @param {number} saturation - How saturated the video should be: 0 = monochrome, 100 = normal color, 200 = super color. * @return {big array} - The modified pixels. */ -function fFxSaturate(uint8,nums) { +function fFxSaturate(array255,nums) { // console.log('START fFxSaturate',nums); - for (let i = 0; i < uint8.data.length; i+=4) { + for (let i = 0; i < array255.data.length; i+=4) { /* add color values together to get average */ - const avg = (uint8.data[i+0] + uint8.data[i+1] + uint8.data[i+2])/3; + const avg = (array255.data[i+0] + array255.data[i+1] + array255.data[i+2])/3; /* apply average to R,G, and B values of each pixel */ - uint8.data[i+0] = (avg*nums[0])+(uint8.data[i+0]*nums[1]); // r - uint8.data[i+1] = (avg*nums[0])+(uint8.data[i+1]*nums[1]); // g - uint8.data[i+2] = (avg*nums[0])+(uint8.data[i+2]*nums[1]); // b + array255.data[i+0] = (avg*nums[0])+(array255.data[i+0]*nums[1]); // r + array255.data[i+1] = (avg*nums[0])+(array255.data[i+1]*nums[1]); // g + array255.data[i+2] = (avg*nums[0])+(array255.data[i+2]*nums[1]); // b } - return uint8; + return array255; } /** - * [invert description] + * [fFxInvert description] * @return {[type]} [description] */ -function fFxInvert (uint8) { - for (var i = 0; i < uint8.data.length; i += 4) { - uint8.data[i+0] = 255 - uint8.data[i+0]; // red - uint8.data[i+1] = 255 - uint8.data[i+1]; // green - uint8.data[i+2] = 255 - uint8.data[i+2]; // blue +function fFxInvert (array255) { + for (var i = 0; i < array255.data.length; i += 4) { + array255.data[i+0] = 255 - array255.data[i+0]; // red + array255.data[i+1] = 255 - array255.data[i+1]; // green + array255.data[i+2] = 255 - array255.data[i+2]; // blue } - return uint8; + return array255; }; - /** * [fFxPixelate description] * @param {big array} data - The pixels. * @param {number} res - Resolution of the pixels: 1 = 1:1, 2 = 1:2, 3 = 1:3, etc. * @return {big array} - The modified pixels. */ -function fFxPixelate(uint8,res) { - // console.log('START fFxPixelate',res); - /* Uint8ClampedArray */ - console.dir(uint8); - console.dir(uint8.data); - // console.log('uint8.data.length: ',uint8.data.length); - // console.log('uint8.width: ',uint8.width); - let compressed = []; - for (let i = 0; i < uint8.data.length; i+=4) { - if ( ((i/4) % res) === 0 ) { +function fFxPixelate(array255,res) { + // console.group('START fFxPixelate',res); + // console.log('array255: ',array255); + // console.dir(array255.data); + + // console.log('array255.data.length: ',array255.data.length); + // console.log('array255.height: ',array255.height); + // console.log('array255.width: ',array255.width); + + + const newLength = array255.data.length/res*res; + // console.log('newLength: ', newLength); + const newHeight = Math.floor(array255.height/res); + // console.log('newHeight: ', newHeight); + const newWidth = Math.floor(array255.width/res); + // console.log('newWidth: ', newWidth); + + let newData = []; + for (let i = 0; i < array255.data.length; i+=4) { + if ( (i % (4*res*res)) === 0 ) { + // console.log('i: ',i); // console.log('slicing'); - compressed.push(uint8.data[i+0]); - compressed.push(uint8.data[i+1]); - compressed.push(uint8.data[i+2]); - compressed.push(uint8.data[i+3]); + newData.push(array255.data[i]); + newData.push(array255.data[i+1]); + newData.push(array255.data[i+2]); + newData.push(array255.data[i+3]); } else { // console.log('NOT slicing'); } } - console.log('compressed.length: ',compressed.length); - console.log('compressed.length/4: ',compressed.length/4); - debugger; - // console.dir(Uint8ClampedArray.from(compressed)); - // uint8.data = new Uint8ClampedArray(compressed); - compressed = Uint8ClampedArray.from(compressed); - // console.dir(compressed); - let newImageData = new ImageData(compressed, (uint8.width/res), (uint8.height/res)); + // console.log('newData: ',newData); + // console.log('newData.length: ',newData.length); + /* need to disable canves scaling and centering in order to properly calculate the canvas dimaensions and length of the ImageData array */ + // console.log('newData.length/(4): ',newData.length/(4)); + // console.dir(Uint8ClampedArray.from(newData)); + // array255.data = new Uint8ClampedArray(newData); + newData = Uint8ClampedArray.from(newData); + // console.dir(newData); + // console.groupEnd(); + // debugger; + let newImageData = new ImageData(newData, newWidth, newHeight); + // let newImageData = new ImageData(newData,1); return newImageData; } diff --git a/19--Webcam_Fun/js/scripts.js b/19--Webcam_Fun/js/scripts.js index 5cde40a714..f638483e7c 100644 --- a/19--Webcam_Fun/js/scripts.js +++ b/19--Webcam_Fun/js/scripts.js @@ -403,7 +403,7 @@ if (navigator.mediaDevices) { } console.log('canvasScale: ',canvasScale); } - fCanvasScale([vWidth,vHeight],[wWidth,wHeight]); + // fCanvasScale([vWidth,vHeight],[wWidth,wHeight]); canvas.width = wWidth; canvas.height = wHeight; @@ -417,8 +417,8 @@ if (navigator.mediaDevices) { // console.log('canvas.style.transform: ',canvas.style.transform); /* center the canvas */ - positionX = (wWidth - vWidth)/2; - positionY = (wHeight - vHeight)/2; + // positionX = (wWidth - vWidth)/2; + // positionY = (wHeight - vHeight)/2; let randoms = []; // random numbers randoms.push(Math.floor(Math.random()*25)+Math.floor(Math.random()*250)); @@ -512,7 +512,7 @@ if (navigator.mediaDevices) { pixels = fFxPixelate(pixels,intPixelate); break; case 'Invert': - // pixels = fFxInvert(pixels); + pixels = fFxInvert(pixels); break; } @@ -738,6 +738,6 @@ window.addEventListener('resize', fMediaQueries); /* fake UI clicks to open controls */ startStream(); -selectFx.selectedIndex = 5; +selectFx.selectedIndex = 6; toggleFxControls(); From a11901c074dc069328a56956f2232440874e0cb2 Mon Sep 17 00:00:00 2001 From: Jeff S Date: Fri, 3 Feb 2017 16:28:41 -0600 Subject: [PATCH 116/119] Proj 19: work on blend F/X function. --- 19--Webcam_Fun/css/theme.css | 2 +- 19--Webcam_Fun/index-jds.html | 26 ++- 19--Webcam_Fun/js/dom.js | 66 +++++++ 19--Webcam_Fun/js/fx-blend.js | 28 +++ 19--Webcam_Fun/js/fx-channelsplit.js | 24 +++ 19--Webcam_Fun/js/fx-chromakey.js | 43 +++++ 19--Webcam_Fun/js/fx-colorize.js | 25 +++ 19--Webcam_Fun/js/fx-invert.js | 19 +++ 19--Webcam_Fun/js/{mirror.js => fx-mirror.js} | 0 19--Webcam_Fun/js/fx-pixelate.js | 56 ++++++ 19--Webcam_Fun/js/fx-saturate.js | 25 +++ 19--Webcam_Fun/js/fx.js | 161 ------------------ 19--Webcam_Fun/js/scripts.js | 125 ++++---------- 13 files changed, 339 insertions(+), 261 deletions(-) create mode 100644 19--Webcam_Fun/js/dom.js create mode 100644 19--Webcam_Fun/js/fx-blend.js create mode 100644 19--Webcam_Fun/js/fx-channelsplit.js create mode 100644 19--Webcam_Fun/js/fx-chromakey.js create mode 100644 19--Webcam_Fun/js/fx-colorize.js create mode 100644 19--Webcam_Fun/js/fx-invert.js rename 19--Webcam_Fun/js/{mirror.js => fx-mirror.js} (100%) create mode 100644 19--Webcam_Fun/js/fx-pixelate.js create mode 100644 19--Webcam_Fun/js/fx-saturate.js delete mode 100644 19--Webcam_Fun/js/fx.js diff --git a/19--Webcam_Fun/css/theme.css b/19--Webcam_Fun/css/theme.css index b0e16a3995..bd36243d5b 100644 --- a/19--Webcam_Fun/css/theme.css +++ b/19--Webcam_Fun/css/theme.css @@ -20,7 +20,7 @@ border-radius:1rem; /* color:rgb(51,51,51); */ color:rgb(255,255,255); - background-color:rgb(204,204,204); + background-color:rgb(153,153,153); /* box-shadow:0 0.125rem 0.5rem 0 rgba(0, 0, 0, 0.5); */ } .input-range {} diff --git a/19--Webcam_Fun/index-jds.html b/19--Webcam_Fun/index-jds.html index b896a5503f..b35fa1b1d0 100755 --- a/19--Webcam_Fun/index-jds.html +++ b/19--Webcam_Fun/index-jds.html @@ -34,9 +34,10 @@

        webcam fun

        - + +