Skip to content

Commit 3fdb013

Browse files
authored
Chapter 15 (#28)
* understanding insert example * adding add files * updating presentation * removing tibble from first app * ending presentation * adding handwriting example * correcting insertUI where argument
1 parent baf9f19 commit 3fdb013

File tree

7 files changed

+846
-36
lines changed

7 files changed

+846
-36
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ bookclub-shinyui.knit.md
1010
bookclub-shinyui_files
1111
libs
1212
_book/*.html
13-
app.R
14-
app2.R
1513

1614
renv/
1715
renv.lock

15_optimize-your-apps-with-custom-handlers.Rmd

Lines changed: 458 additions & 34 deletions
Large diffs are not rendered by default.

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Imports:
1515
bookdown,
1616
bs4Dash,
1717
DiagrammeR,
18+
htmltools,
1819
httpuv,
1920
jsonlite,
2021
purrr,
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
library(shiny)
2+
3+
dropdownDeps <- function(){
4+
htmltools::htmlDependency(name = "handwriting",
5+
version = "1.0.0",
6+
src = c(file = "."),
7+
script = "handwriting.canvas.js")
8+
}
9+
10+
11+
ui = fluidPage(
12+
dropdownDeps(),
13+
htmltools::HTML('
14+
15+
<div>
16+
<span style="display : inline-block">
17+
PenSize <span id="lineWidth">3</span><input type="range" id="penSize" min="1" max="30" value="3">
18+
<br>
19+
<canvas id="canvas" width="400" height="400" style="border: 2px solid; cursor: crosshair;"></canvas>
20+
<br>
21+
<form>
22+
Language:
23+
<select id="language">
24+
<option value="zh_TW" selected="selected">Chinese</option>
25+
<option value="ja">Japanese</option>
26+
<option value="en">English</option>
27+
</select>
28+
</form>
29+
<br>
30+
<button onclick="canvas.erase();">Erase</button>
31+
<button onclick="
32+
var e = document.getElementById(\'language\');
33+
canvas.setOptions({language: e.options[e.selectedIndex].value});
34+
canvas.recognize();
35+
">Send</button>
36+
<button onclick="canvas.undo()">Undo</button>
37+
<button onclick="canvas.redo()">Redo</button>
38+
<br>
39+
<p id="result2">result: <span id="result"></span></p>
40+
</span>
41+
<script type="text/javascript" src="handwriting.canvas.js"></script>
42+
<script type="text/javascript" defer="">
43+
var canvas = new handwriting.Canvas(document.getElementById(\'canvas\'), 3);
44+
var width = document.getElementById("demo").clientWidth
45+
canvas.cxt.canvas.width = width < 400 ? width : 400;
46+
canvas.cxt.canvas.height = width < 400 ? width : 400;
47+
canvas.setCallBack(function(data, err) {
48+
if (err) throw err;
49+
else document.getElementById("result").innerHTML = data;
50+
});
51+
canvas.set_Undo_Redo(true, true);
52+
var penSize = document.getElementById("penSize");
53+
penSize.addEventListener("mousemove", function() {
54+
document.getElementById("lineWidth").innerHTML = penSize.value;
55+
});
56+
penSize.addEventListener("change", function(){
57+
canvas.setLineWidth(penSize.value);
58+
});
59+
</script>
60+
</div>
61+
')
62+
)
63+
64+
65+
66+
server <- function(input, output, session) {
67+
68+
observeEvent(input$myinput,{
69+
removeUI(selector = "#result")
70+
71+
insertUI(selector = "#result2",
72+
ui = paste0(as.character(input$myinput), collapse = " "),
73+
where = "beforeEnd")
74+
})
75+
76+
}
77+
78+
shinyApp(ui, server)
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
(function(window, document) {
2+
3+
// Establish the root object, `window` (`self`) in the browser,
4+
// or `this` in some virtual machines. We use `self`
5+
// instead of `window` for `WebWorker` support.
6+
var root = typeof self === 'object' && self.self === self && self || this;
7+
8+
// Create a safe reference to the handwriting object for use below.
9+
var handwriting = function(obj) {
10+
if (obj instanceof handwriting) return obj;
11+
if (!(this instanceof handwriting)) return new handwriting(obj);
12+
this._wrapped = obj;
13+
};
14+
15+
root.handwriting = handwriting;
16+
17+
handwriting.Canvas = function(cvs, lineWidth) {
18+
this.canvas = cvs;
19+
this.cxt = cvs.getContext("2d");
20+
this.cxt.lineCap = "round";
21+
this.cxt.lineJoin = "round";
22+
this.lineWidth = lineWidth || 3;
23+
this.width = cvs.width;
24+
this.height = cvs.height;
25+
this.drawing = false;
26+
this.handwritingX = [];
27+
this.handwritingY = [];
28+
this.trace = [];
29+
this.options = {};
30+
this.step = [];
31+
this.redo_step = [];
32+
this.redo_trace = [];
33+
this.allowUndo = false;
34+
this.allowRedo = false;
35+
cvs.addEventListener("mousedown", this.mouseDown.bind(this));
36+
cvs.addEventListener("mousemove", this.mouseMove.bind(this));
37+
cvs.addEventListener("mouseup", this.mouseUp.bind(this));
38+
cvs.addEventListener("touchstart", this.touchStart.bind(this));
39+
cvs.addEventListener("touchmove", this.touchMove.bind(this));
40+
cvs.addEventListener("touchend", this.touchEnd.bind(this));
41+
this.callback = undefined;
42+
this.recognize = handwriting.recognize;
43+
};
44+
/**
45+
* [toggle_Undo_Redo description]
46+
* @return {[type]} [description]
47+
*/
48+
handwriting.Canvas.prototype.set_Undo_Redo = function(undo, redo) {
49+
this.allowUndo = undo;
50+
this.allowRedo = undo ? redo : false;
51+
if (!this.allowUndo) {
52+
this.step = [];
53+
this.redo_step = [];
54+
this.redo_trace = [];
55+
}
56+
};
57+
58+
handwriting.Canvas.prototype.setLineWidth = function(lineWidth) {
59+
this.lineWidth = lineWidth;
60+
};
61+
62+
handwriting.Canvas.prototype.setCallBack = function(callback) {
63+
this.callback = callback;
64+
};
65+
66+
handwriting.Canvas.prototype.setOptions = function(options) {
67+
this.options = options;
68+
};
69+
70+
71+
handwriting.Canvas.prototype.mouseDown = function(e) {
72+
// new stroke
73+
this.cxt.lineWidth = this.lineWidth;
74+
this.handwritingX = [];
75+
this.handwritingY = [];
76+
this.drawing = true;
77+
this.cxt.beginPath();
78+
var rect = this.canvas.getBoundingClientRect();
79+
var x = e.clientX - rect.left;
80+
var y = e.clientY - rect.top;
81+
this.cxt.moveTo(x, y);
82+
this.handwritingX.push(x);
83+
this.handwritingY.push(y);
84+
};
85+
86+
87+
handwriting.Canvas.prototype.mouseMove = function(e) {
88+
if (this.drawing) {
89+
var rect = this.canvas.getBoundingClientRect();
90+
var x = e.clientX - rect.left;
91+
var y = e.clientY - rect.top;
92+
this.cxt.lineTo(x, y);
93+
this.cxt.stroke();
94+
this.handwritingX.push(x);
95+
this.handwritingY.push(y);
96+
}
97+
};
98+
99+
handwriting.Canvas.prototype.mouseUp = function() {
100+
var w = [];
101+
w.push(this.handwritingX);
102+
w.push(this.handwritingY);
103+
w.push([]);
104+
this.trace.push(w);
105+
this.drawing = false;
106+
if (this.allowUndo) this.step.push(this.canvas.toDataURL());
107+
};
108+
109+
110+
handwriting.Canvas.prototype.touchStart = function(e) {
111+
e.preventDefault();
112+
this.cxt.lineWidth = this.lineWidth;
113+
this.handwritingX = [];
114+
this.handwritingY = [];
115+
var de = document.documentElement;
116+
var box = this.canvas.getBoundingClientRect();
117+
var top = box.top + window.pageYOffset - de.clientTop;
118+
var left = box.left + window.pageXOffset - de.clientLeft;
119+
var touch = e.changedTouches[0];
120+
touchX = touch.pageX - left;
121+
touchY = touch.pageY - top;
122+
this.handwritingX.push(touchX);
123+
this.handwritingY.push(touchY);
124+
this.cxt.beginPath();
125+
this.cxt.moveTo(touchX, touchY);
126+
};
127+
128+
handwriting.Canvas.prototype.touchMove = function(e) {
129+
e.preventDefault();
130+
var touch = e.targetTouches[0];
131+
var de = document.documentElement;
132+
var box = this.canvas.getBoundingClientRect();
133+
var top = box.top + window.pageYOffset - de.clientTop;
134+
var left = box.left + window.pageXOffset - de.clientLeft;
135+
var x = touch.pageX - left;
136+
var y = touch.pageY - top;
137+
this.handwritingX.push(x);
138+
this.handwritingY.push(y);
139+
this.cxt.lineTo(x, y);
140+
this.cxt.stroke();
141+
};
142+
143+
handwriting.Canvas.prototype.touchEnd = function(e) {
144+
var w = [];
145+
w.push(this.handwritingX);
146+
w.push(this.handwritingY);
147+
w.push([]);
148+
this.trace.push(w);
149+
if (this.allowUndo) this.step.push(this.canvas.toDataURL());
150+
};
151+
152+
handwriting.Canvas.prototype.undo = function() {
153+
if (!this.allowUndo || this.step.length <= 0) return;
154+
else if (this.step.length === 1) {
155+
if (this.allowRedo) {
156+
this.redo_step.push(this.step.pop());
157+
this.redo_trace.push(this.trace.pop());
158+
this.cxt.clearRect(0, 0, this.width, this.height);
159+
}
160+
} else {
161+
if (this.allowRedo) {
162+
this.redo_step.push(this.step.pop());
163+
this.redo_trace.push(this.trace.pop());
164+
} else {
165+
this.step.pop();
166+
this.trace.pop();
167+
}
168+
loadFromUrl(this.step.slice(-1)[0], this);
169+
}
170+
};
171+
172+
handwriting.Canvas.prototype.redo = function() {
173+
if (!this.allowRedo || this.redo_step.length <= 0) return;
174+
this.step.push(this.redo_step.pop());
175+
this.trace.push(this.redo_trace.pop());
176+
loadFromUrl(this.step.slice(-1)[0], this);
177+
};
178+
179+
handwriting.Canvas.prototype.erase = function() {
180+
this.cxt.clearRect(0, 0, this.width, this.height);
181+
this.step = [];
182+
this.redo_step = [];
183+
this.redo_trace = [];
184+
this.trace = [];
185+
};
186+
187+
function loadFromUrl(url, cvs) {
188+
var imageObj = new Image();
189+
imageObj.onload = function() {
190+
cvs.cxt.clearRect(0, 0, this.width, this.height);
191+
cvs.cxt.drawImage(imageObj, 0, 0);
192+
};
193+
imageObj.src = url;
194+
}
195+
196+
handwriting.recognize = function(trace, options, callback) {
197+
if (handwriting.Canvas && this instanceof handwriting.Canvas) {
198+
trace = this.trace;
199+
options = this.options;
200+
callback = this.callback;
201+
} else if (!options) options = {};
202+
var data = JSON.stringify({
203+
"options": "enable_pre_space",
204+
"requests": [{
205+
"writing_guide": {
206+
"writing_area_width": options.width || this.width || undefined,
207+
"writing_area_height": options.height || this.width || undefined
208+
},
209+
"ink": trace,
210+
"language": options.language || "zh_TW"
211+
}]
212+
});
213+
var xhr = new XMLHttpRequest();
214+
xhr.addEventListener("readystatechange", function() {
215+
if (this.readyState === 4) {
216+
switch (this.status) {
217+
case 200:
218+
var response = JSON.parse(this.responseText);
219+
var results;
220+
if (response.length === 1) callback(undefined, new Error(response[0]));
221+
else results = response[1][0][1];
222+
if (!!options.numOfWords) {
223+
results = results.filter(function(result) {
224+
return (result.length == options.numOfWords);
225+
});
226+
}
227+
if (!!options.numOfReturn) {
228+
results = results.slice(0, options.numOfReturn);
229+
}
230+
Shiny.setInputValue('myinput', results, {priority: 'event'});
231+
break;
232+
case 403:
233+
callback(undefined, new Error("access denied"));
234+
break;
235+
case 503:
236+
callback(undefined, new Error("can't connect to recognition server"));
237+
break;
238+
}
239+
240+
241+
}
242+
});
243+
xhr.open("POST", "https://www.google.com.tw/inputtools/request?ime=handwriting&app=mobilesearch&cs=1&oe=UTF-8");
244+
xhr.setRequestHeader("content-type", "application/json");
245+
xhr.send(data);
246+
};
247+
248+
})(window, document);
93.4 KB
Loading

0 commit comments

Comments
 (0)