class: title
Hello World Wide Web
JavaScript for Shiny Users
Garrick Aden-Buie
rstudio::conf(2020, "JavaScript for Shiny Users")
--- class: break break-javascript bottom right ## JS<br>CSS<br>HTML<br>...WTF? --- name: how-it-works layout: true # How does the web work? ??? * Browser requests `rstudio.com` * gets `rstudio.com/index.html` * `index.html` says here's the document * and you also need these other files * browser reads document structure, styles, javascript * builds a web page and hands it to you * what `index.html` says it should be and what the page *is* when you see it are very different --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-04.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-05.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-06.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-07.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-08.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-09.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-10.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-11.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-12.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-13.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-14.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-15.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-16.jpg') background-size: contain background-position: top left --- class: animated fadeIn background-image: url('assets/img/intro/how-web-works/how-web-works-17.jpg') background-size: contain background-position: top left --- layout: false class: fullscreen animated zoomIn background-image: url('assets/img/intro/color-by-number.png') background-size: cover background-position: top left ??? * HTML tells the browser **what**: * content * images * other files --- class: fullscreen background-image: url('assets/img/intro/anna-kolosyuk-D5nh6mCW52c-unsplash.jpg') background-size: cover background-position: top left ??? * CSS tells the browser **how** to show things to you --- class: fullscreen background-image: url('assets/img/intro/alice-achterhof-FwF_fKj5tBo-unsplash.jpg') background-size: cover background-position: 0 -50px ??? * JavaScript can step in at any point and mess with the whole process --- name: button-example class: fullscreen h-100 .pa2.pl3[ ## HTML ] .fl.w-70.pa2.pl3.nt3[ ```html <button id="button-demo" value='0'> 👍 Plus one </button> ``` ] .fr.w-30.pa2.pl3.pt3.nt3[ <button value='0'>👍 Plus one</button> ] ??? Go through the example twice... The first time, just showing the basics, focusing on the role of the languages. The second time, talk through - connected via `id` - css controls appearance - note: appearance _in states_ so sometimes it feels like it does something but it doesn't change the HTML - js can change the HTML, change the styles, move things around, react etc. Finally use last block as quick intro to JS --- class: fullscreen h-100 .pa2.pl3[ ## CSS ] .fl.w-70.pa2.pl3.nt3[ ```css #button-demo { color: #4d8dc9; background-color: white; border: 2px solid #4d8dc9; padding: 0.5em 1em; } ``` <style type="text/css"> #button-demo { color: #4d8dc9; background-color: white; border: 2px solid #4d8dc9; padding: 0.5em 1em; } </style> ] <div id="button-demo-no-hover"> .fr.w-30.pa2.pl3.pt3.nt3[ <button id="button-demo" value='0'>👍 Plus one</button> ] </div> <style> #button-demo-no-hover #button-demo { background-color: white; border: 2px solid #4d8dc9; color: #4d8dc9; } #button-demo-no-hover #button-demo { transform: scale(1); } </style> --- class: fullscreen h-100 .pa2.pl3[ ## CSS ] .fl.w-70.pa2.pl3.nt3[ ```css #button-demo { color: #4d8dc9; background-color: white; border: 2px solid #4d8dc9; padding: 0.5em 1em; } ``` ```css #button-demo:hover { background-color: #4d8dc9; color: white; } ``` <style type="text/css"> #button-demo:hover { background-color: #4d8dc9; color: white; } </style> ] <div id="button-demo-no-active"> .fr.w-30.pa2.pl3.pt3.nt3[ <button id="button-demo" value='0'>👍 Plus one</button> ] </div> <style>#button-demo-no-active #button-demo { transform: scale(1); }</style> --- class: fullscreen h-100 .pa2.pl3[ ## CSS ] .fl.w-70.pa2.pl3.nt3[ ```css #button-demo { color: #4d8dc9; background-color: white; border: 2px solid #4d8dc9; padding: 0.5em 1em; } #button-demo:hover { background-color: #4d8dc9; color: white; } ``` ```css #button-demo:active { transform: scale(0.9); } ``` <style type="text/css"> #button-demo:active { transform: scale(0.9); } </style> ] .fr.w-30.pa2.pl3.pt3.nt3[ <button id="button-demo" value='0'>👍 Plus one</button> ] --- class: fullscreen h-100 .pa2.pl3[ ## JS ] .fl.w-70.pa2.pl3.nt3[ ```js const btn = document.getElementById('button-demo') ``` ```js btn.addEventListener('click', function() { let clicks = parseInt(btn.value) clicks = clicks + 1 btn.value = clicks btn.innerHTML = `👍 Plus one (${clicks})` console.log('Clicks: ' + clicks) }) ``` <div id="out-button-demo-js"><pre></pre></div> ] <div id="button-demo-full"> .fr.w-30.pa2.pl3.pt3.nt3[ <button id="button-demo" value='0'>👍 Plus one</button> ] </div> <div id="out-button-demo-js-reset"><pre></pre></div> <style type="text/css"> #out-button-demo-js-reset { display: none; } </style> --- name: motivation class: break break-shiny huge # Shiny + .js .marker.f5[What can we do with Shiny and Javascript?] --- # Use color to give feedback .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/01-feedback-color.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/01-feedback-color.html">iframe content</a> </div></div> ] --- # Hold your horses... .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/02-feedback-icon-animation_initial.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/02-feedback-icon-animation_initial.html">iframe content</a> </div></div> ] --- # Waiting is easier with communication .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/02-feedback-icon-animation_solution.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/02-feedback-icon-animation_solution.html">iframe content</a> </div></div> ] --- # Direct attention with animation .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/03-feedback-animation-wiggle.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/03-feedback-animation-wiggle.html">iframe content</a> </div></div> ] --- # Send messages to your users .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/04-feedback-update-text.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/04-feedback-update-text.html">iframe content</a> </div></div> ] --- # Guide users through your app .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/05-control-focus.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/05-control-focus.html">iframe content</a> </div></div> ] --- # Add keyboard shortcuts .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/06-control-keyboard-events.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/06-control-keyboard-events.html">iframe content</a> </div></div> ] --- layout: true # Make R Markdown awesome-r --- .panelset[ .panel[.panel-name[pkg-stats.Rmd] ```markdown ## ggplot2 {.pkg-stats} downloads : 846k/month stars : 4.2k forks : 1.5k ``` ] .panel[.panel-name[pkg-stats.html] ```html <h2 class="pkg-stat" id="ggplot2">ggplot2</h2> <dl> <dt>downloads</dt> <dd>846k/month</dd> <dt>stars</dt> <dd>4.2k</dd> <dt>forks</dt> <dd>1.5k</dd> </dl> ``` ] .panel[.panel-name[Browser] .relative.w-100.h-abs-475[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/08-design-rewrite_initial.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/08-design-rewrite_initial.html">iframe content</a> </div></div> ]] ] --- .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/08-design-rewrite_solution.html" class="fullscreen-iframe-scale-150"> <a href="assets/html/motivate/08-design-rewrite_solution.html">iframe content</a> </div></div> ] --- layout: false # Don't work too hard .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/07-design-add-content.html" class="fullscreen-iframe-scale-150"> <a href="assets/html/motivate/07-design-add-content.html">iframe content</a> </div></div> ] --- # Use JavaScript libraries for **fun** .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/09-jslib-typerjs.html" class="fullscreen-iframe-scale-200"> <a href="assets/html/motivate/09-jslib-typerjs.html">iframe content</a> </div></div> ] --- # Use JavaScript libraries for **profit** .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/10-jslib-frappe-charts.html" class="fullscreen-iframe-scale-125"> <a href="assets/html/motivate/10-jslib-frappe-charts.html">iframe content</a> </div></div> ] --- # Use JavaScript libraries for **profit** .relative.w-100.h-100.ph2[ <div class="fullscreen-iframe-container"><div data-iframe data-src="assets/html/motivate/11-jslib-frappe-charts-extended.html" class="fullscreen-iframe-scale-125"> <a href="assets/html/motivate/11-jslib-frappe-charts-extended.html">iframe content</a> </div></div> ] --- layout: true # Workshop goals ??? One major reason for focusing on some of the fundamentals is that it's an expected baseline in much of the documentation. Web people and libraries assume you're going to do web things, as anyone whose asked a shiny specific webdev question on stack overflow knows. R and Shiny package docs focus on being productive with the tools, not necessarily going deep. _How does anybody learn this?_ Having a solid mental model of what web dev is supposed to be like is super helpful. --- .w-two-thirds.mh-a[ ![](assets/img/intro/front-back.png) ] --- .w-80.mh-a[ ![](assets/img/intro/front-back-shiny.jpg) ] --- class: center middle # Next: [Maiden Voyage (How to WWW)](how-to-www.html)