第 7 章 Web application
Webpage
Everything is fully downloaded to your computer.
Interaction happens within your computer.
Web service
Only web UI is downloaded to your computer.
Interaction may require sending requests to remote computers (aka server) to obtain necessary data to update your browser view.
You need to know how to build a webpage in order to build a web service.
7.1 Webpage
7.1.1 The basic
a set of documents saved in a project folder, which is called root directory for your webpage.
Documents generally contain three major parts:
.html
.css
.js
There are other parts such as image, data, etc.
7.1.2 A simple website project
Run:
The following function:
project_html_create(
main_file="index.html",
type="plain", # or bs : bootstrap
dirlib="webProject0",
structure=c(
"js",
"css",
"assets")
)
creates a website project under your ./webProject0
folder, with a file structure:
levelName
1 index.html
2 ¦–/js
3 ¦–/css
4 °–/assets
index.html is the main webpage file for browser to read. Its
style is governed by .css,
interaction is governed by .js,
image, audio, video files are saved in
/assets
Though there are three parts, .css
, .js
files and asset files, they can be contained within .html
so that the html document is self-contained.
self-contained: you can share only the
.html
to others.- all
.css
,.js
, and asset files are included inside.html
- all
not self-contained: to share a html, you need to share the entire project folder.
- some
.css
in/css
,.js
in/js
, asset files in/assets
.
- some
試著用Rmardown knit一份html檔。 使用兩種output的設定:
設定1:
設定2:
7.1.3 file path
In a .html
, when it refers to some external file (js, css or asset), the following two file path expression are common:
img/...
: means at the .html
file directory there is a folder called img
.
levelName
1 /
2 ¦–an .html with ‘img/a.png’
3 °–img/
4 °–a.png
./img/
: means at the root directory there is a folder called img
.
levelName
1 ./
2 ¦–index.html
3 ¦–page/
4 ¦ °–p1.html with ‘./img/a.png’
5 °–img/
6 °–a.png
7.1.5 div and span
加到index.html
body:
inline element: span
block element: div
7.1.6 attributes and style
attributes complete an element’s definition:
For example, an image element needs to know the location of image file (src attr), width and height of the image box size (width and height attrs):
cosmetic appearance of an element is defined through style attribute:
7.1.7 CSS
An element’s style can also be defined outside the element style attribute:
Within .html
, use <style>
tag
<style>
img, #myTargetElement, .myBlue {
border-style: dashed;
padding: 15px 15px;
background-color: aliceblue
}
</style>
placed inside header or the beginning of body
img, #myTargetElement, .myBlue
is called CSS selector. It defines which element(s) should the style applied to. (#
for id attr,.
for class attr)
id獨一無二,每個id在一個html檔只能有一個。
- class可用在多數個element。
Put the previous style element in header, and the following in body:
7.1.7.1 External .css
file
執行:
將my.css貼如下內容,並把檔案放到css/
目錄下:
img, #myTargetElement, .myBlue {
border-style: dashed;
padding: 15px 15px;
background-color: aliceblue
}
在html header加入:
7.1.8 Javascript
For a start, it is not a good idea to mix up your HTML and your JavaScript, as it becomes hard to parse — keeping your JavaScript all in one place is better; if it is in a separate file you can apply it to multiple HTML documents.
在html裡用<script>
tag來寫Javascript:
7.1.8.2 DOM (Document Object Method)
JS把html document的每個<tab>...</tab>
視為一個Object,並賦予它許多有趣的可能變化方式,稱為Method。
首先,要拿出某個element成為Document object:
- get an element:
document.getElementBy...()
.getElementById(‘{idname}’)
- 選一個element為目標,增加
id="myTarget"
這個attribute。
會選出這個element object。
document.querySelector(“{CSS selector}”)
每個element可以用CSS selector描述它的位置。在chrome developer Elements tab,選到所要element,按右鍵選Copy JS Path, 其內容即為完整
再來可以取得element裡的content, attribute, 或style並加以改變:
access element
- content:
.innerHTML
- attribute:
.attribute
- style of property:
.style.{property}
; or
- set attribute value method:
.setAttribute({attribute},{value})
- content:
開啟一個網頁,選其中一個element,並執行以下JS,讓它的內容消失:
7.1.8.3 Event
getElement後addEventListener
- Event handler: the function that takes action.
7.1.8.5 external include
在html inline寫入:
在Rmd裡外部引入d3.js :
7.1.9 SVG
dir.create(
"./1211"
)
download.file("https://raw.githubusercontent.com/tim8537099/course-108-1-inclass-datavisualization/master/example/tet.Rmd",
destfile="1211/tet.Rmd"
)
download.file("https://github.com/tim8537099/course-108-1-inclass-datavisualization/blob/master/example/plot_us.Rda?raw=true",
destfile="1211/plot_us.Rda"
)
file.edit("1211/tet.Rmd")
7.1.9.1 gridSVG package
會存出plot1.svg
7.1.9.2 引入SVG
SVG icons:
Fontawesome: https://fontawesome.com/
Feather: https://feathericons.com/
7.1.9.3 Select SVG element
https://benfrain.com/selecting-svg-inside-tags-with-javascript/
http://xn--dahlstrm-t4a.net/svg/html/get-embedded-svg-document-script.html
svg and javascript: http://www.petercollingridge.co.uk/tutorials/svg/interactive/javascript/
分成「SVG內部JS」(即JS位於<svg>
裡,Internal JS)與「SVG外部JS」(External JS)兩種,這裡只講會用到的External JS。然SVG又可分成「html內含SVG」及「html外部引入SVG」兩種:
html內含SVG+External JS:JS取SVG元素和以前所學相同。
html外部引入SVG + External JS:
<script type="text/javascript">
window.addEventListener("load", function() { //確保load完html才開始
var svgObject = document.getElementById('svg-object').contentDocument; //取出<object>裡的contentDocument (這才算進入SVG裡)
var svg = svgObject.getElementById('external-1'); //和以前同樣取法
console.log(svg);
});
</script>
當html引用到外部檔案時,必需用http serve的方式瀏覽,也就是要把你的電腦虛擬成一個server,只能用http://
方式開啟網頁(注意不是https),在R console執行:
範例:
執行以下程序得到一個getSVGelement資料匣,以local serve方式打開html檔:
download.file("https://www.dropbox.com/s/99tfecfkblpsij8/getSVGelement.zip?dl=1",
destfile = "getSVGelement.zip")
unzip("getSVGelement.zip")
試著:
滑鼠點擊黃圓圈,它會變成藍圓圈。
滑鼠點擊右邊三角帽,左邊的圓圈會變粉紅色。
以下做法當滑鼠hover在三角帽時其顏色變透明,供大家參考:
7.1.10 JSON
JavaScript Object Notation: text, written with JavaScript object notation.
網路資料收送的標準格式。
JSON Object透過
JSON.parse()
轉成JS Object進一步在JS中當變數使用。若JS Object想轉成JSON儲存可透過
JSON.stringify()
。https://www.copterlabs.com/json-what-it-is-how-it-works-how-to-use-it/
JavaScript data types:
var cars = ["Saab", "Volvo", "BMW"]; //JS array
var length = 16; // Number
var lastName = "Johnson"; // String
var x = {firstName:"John", lastName:"Doe"}; // Object
JSON content:
JSON objects are surrounded by curly braces {}:
JSON objects are written in key/value pairs.
Keys must be strings, and values must be a valid JSON data type (string, number, object, array, boolean or null).JSON arrays are surrounded by brackets []:
Array values must be of type string, number, object, array, boolean or null.
7.1.10.1 Inline使用
- JSON內容包覆在
<script type="application/json">...</script>
中。
<script id='json1' type="application/json">
{
"name": "John",
"age": 30,
"cars": [ "Ford", "BMW", "Fiat" ]
}
</script>
- 用
getElementById('json1').innerHTML
方式取出,再用JSON.parse()
轉成JS object使用:
7.1.10.2 R物件轉JSON
- JSON內容可用
jsonlite::toJSON()
產生,用writeLines
存成外部json檔。
範例:將R oject轉成html下的JSON element mtcars dataframe存成mtcars.json檔
# ggplot2裡的mtcars dataframe
mtcars %>%
jsonlite::toJSON() %>% ## (1)
writeLines("mtcars.json") ## (2)
(1)將R物件轉JSON,若沒有(2),只要在code chunk外用
<script type="application/json>...</script>
包覆knit完就成為inline使用的JSON資料(2)將JSON另外存在
mtcars.json
檔中。
7.1.10.3 外部JSON inline使用
- JSON存在外部檔案,但在HTML想用
<script>
inline使用。
要在HTML產生inline <script>
,只要在RMarkdown裡:
當knit成html時,此段內容會變成
要在JavaScript引入此資料時,可使用:
7.1.10.4 external include
前一小節是把JSON放在html裡,另外也可以不嵌入JSON而採AJAX的XMLHttpRequest進行外部資料請求(要用時才請求)。
在html裡使用以下JS引入
function fetchJSONFile(path, callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var data = JSON.parse(httpRequest.responseText);
if (callback) callback(data);
}
}
};
httpRequest.open('GET', path);
httpRequest.send();
}
需要用到mtcars.json
時,以下面js方式引入及使用:
fetchJSONFile('mtcars.json',jdata=>{
console.log(jdata); //Just to check what jdata is like
//jdata即為mtcars.json內容,下面接上要使用它做的事:
})
當某個事件觸發的事情需要外部資料來完成時,適合使用此方法。
https://www.tutorialsteacher.com/d3js/loading-data-from-file-in-d3js
xmlhttp Object: https://www.w3schools.com/js/js_ajax_http.asp
JSON parse: https://www.w3schools.com/js/js_json_parse.asp
若有引入jQuery則可使用以下js替代:
7.1.11 Online form
包含在<form>...</form>
裡,使用者最後輸入/選擇的值主要由裡頭的<input>
, <select>
, <textarea>
這些input element的attrs. 或innerHTML內容決定。
對<form>
裡的input element進行:
get element
addEventListener可以使用哪些events:
見Form Events: https://www.w3schools.com/tags/ref_eventattributes.asp
click, change, submit
handler內容:
- 不同input要收集的是什麼? attrs? (可用
.attrName
取出) innerHTML?
- 不同input要收集的是什麼? attrs? (可用
JavaScript: serialize a form as JSON:
https://codepen.io/ntpumartin/pen/MWYmypq
引入bootstrap 4到planHTML.Rmd: https://getbootstrap.com/docs/4.4/getting-started/introduction/
7.2 不同步傳輸
in_header: JS需要先load完網頁layout才會正常的。
after_body: 網頁layout完成才需要執行的JS;
- 也可以:
網頁外部訊息的pull in多數不是同步的,有時會造成你js效果失效。此時可以把你的js, 包在:
7.3 Webpage hosting
bookdown.org: register at https://bookdown.org/connect/ first.
github.com: set up your github page according to https://pages.github.com/.
local serve:
servr::httd(port=8000)
可在browser打http://localhost:8000進入工作目錄(注意不是https)
7.4 flexdashboard
R Markdown to Markdown: code chunks are processed.
echo
: should code present in the webpage. (=T if yes)eval
: should code be processed. (=T if yes)
Markdown to HTML: convert anything not html to html.
- If it is already html, leave it as it is.
7.4.1 Setup
先安裝flexdashboard
File > New File > R Markdown > From Template > Flex Dashboard
- Design your dashboard.
Knit your Rmd.
Publish to your bookdown.org
7.4.2 Publish
For the first time to publish, at step 4 you press the publish icon:
Select RStudio Connect.
Select Publish finished document only.
Select Add new account.
Type bookdown.org, click next.
Once it is published to bookdown.org, you have to change Who can view this document from you to Anyone, and Save.
- Copy the URL under Custom URL (which is your webpage url)
7.4.3 External setup
執行以下程式
c("external/header","external/before_body","external/after_body") %>%
lapply(dir.create, recursive=T)
在frontmatter的flexdashboard::flex_dashboard:
enter換行後,可輸入
includes:
in_header: ["檔案1", "檔案2", ...]
before_body: ["檔案1", "檔案2", ...]
after_body: ["檔案1", "檔案2", ...]
它會將knit後的html成品加上檔案中的html scripts.
典型html:
<html>
<header>
{in_header加在這}
</header>
<body>
{before_body加在這}
...
{after_body加在這}
</body>
</html>
7.4.3.1 Fontawesome Example
以下指令會創一個headerScript.html
檔:
請在裡面加上:
<!---Fontaweseom-->
<script src="https://kit.fontawesome.com/fda67dba4d.js" crossorigin="anonymous"></script>
恭喜你,你已可以在Rmd文件中自由使用fontawesome。
- Find icon: https://fontawesome.com/icons?d=gallery
執行以下程式:
利用
html_create_plain("xxx.html")
產生一個單純的html檔,檔名xxx可自取。(此函數會同時以browser及RStudio打開檔案呈現)
引入fontawesome.
在body裡加上
<i class="far fa-address-card"></i>
refresh browser view.
<i>
是inline element, 可以放在文字訊息字裡行間當成一個字使用。
7.4.4 Inline web language
R Markdown allows you to intertwine web languages (html, css, js) inside the document:
7.6 流程圖:SVG生成與引入
以下流程圖說明如何形成獨立SVG檔以便融入flexdashboard使用。