-
Notifications
You must be signed in to change notification settings - Fork 0
/
canvas.html
257 lines (213 loc) · 10.4 KB
/
canvas.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="canvas.css" />
<title>Document</title>
</head>
<body>
<div id="controls">
<button id="playButton" onclick="togglePlay();">Play</button>
<!-- <button onclick="pause();">Pause</button> -->
<button onclick="toggleTimestamp()">Timestamp</button>
<button onclick="toggleInfo()">Info</button>
</div>
<div id="container">
<canvas id="canvas" class="over"></canvas>
<video id="video" src="modern_times1.mp4" class="over" playsinline></video>
<audio id="audio">
<source src="pop.wav" type="audio/wav">
Your browser does not support the audio tag.
</audio>
<div id="info" class="over hide">
This app shows factual information about a film while it's playing.
It uses a concept called "pop ups" which became popular in the mid-90s.
The app relies on a Canvas overlay where the popups are generated and shown.
The Play/pause button plays the film, but will not prevent pop-ups being drawn
on the canvas. <br><br>
This contains about 1 minute of Charlie Chaplin's "Modern Times".
<br>
<br>
For scaling to the background, browser width is best at ~1130px
</div>
</div>
<script>
//Global definitions
var video = document.getElementById("video");
var canvas = document.getElementById("canvas");
var audio = document.getElementById("audio");
var ctx = canvas.getContext("2d");
//Each of these should have their own draw method to call.
var animateObjects = [];
var timestamp = new Timestamp(ctx);
/*
Draws a "pop up video" bubble.
*/
function drawBubble(context, x, y, height, width){
let radius = height/2;
let lineWidth = 2;
//left Arc
context.beginPath();
context.arc(x,y,radius, 0.5 * Math.PI, 1.5 * Math.PI);
context.fillStyle = "#fff";
context.fill();
context.strokeStyle = "#000";
context.lineWidth = lineWidth;
context.stroke();
//top line
context.beginPath();
context.moveTo(x,y - radius);
context.lineTo(x + width,y - radius);
context.stroke();
//bottom line
context.beginPath();
context.moveTo(x,y + radius);
context.lineTo(x + width,y + radius);
context.stroke();
//fill background
context.fillStyle = "#fff";
context.fillRect(x, y - radius + (lineWidth/2), width, (radius * 2) - lineWidth);
//right arc
context.beginPath();
context.arc(x + width,y,radius, 1.5 * Math.PI, 0.5 * Math.PI);
context.fillStyle = "#fff";
context.fill();
context.strokeStyle = "#000";
context.lineWidth = lineWidth;
context.stroke();
}
function drawTest(){
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = 20;
ctx.beginPath();
ctx.arc(100,60, 30, 2 * Math.PI, false);
ctx.fillStyle = 'green';
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = '#003300';
ctx.stroke();
}
//Popup object.
function PopUp(text, x, y, startTime, endTime, context) {
this.text = text
this.x = x;
this.y = y;
this.radius = 0;
this.width = 0;
this.startTime = startTime;
this.endTime = endTime;
this.animate = true; //Whether the popup should be drawn or not.
this.audioPlayed = false;
this.currentRadius = 0; //initialize to not-visible.
this.currentWidth = 0; //Initial the initial width.
const charHeight = 14;
//Previously these were arguments. They should be calculated instead.
let radius = 10;
var lines = this.text.split("\n"); //the number of lines in the text.
let width = 6.35 * lines[0].length; //Calculated by emperical testing.
let height = (charHeight * lines.length) + 15;
//target values are set at initialization. They are not exposed.
let targetWidth = width;
let targetRadius = radius;
this.draw = function(){
let time = document.querySelector("#video").currentTime;
if(this.audioPlayed === false && time > this.startTime) {
audio.play();
this.audioPlayed = true;
}
if(time > this.startTime && time < this.endTime) {
if(this.radius < targetRadius) {
this.radius += 2;
}else if(this.width < targetWidth) {
this.width += 15;
}
this.time -= 1; //Decrement time, described in frames.
drawBubble(context, this.x, this.y, height, this.width);
let lineStart = this.y - targetRadius;
context.save();
context.beginPath();
// context.fillStyle = "#000";
// context.fillRect(this.x, this.y - height/2, this.width, height);
// This rectangle renders the space that will be clipped around the text to be displayed.
context.rect(this.x, this.y - height/2, this.width, height);
context.clip();
context.font = "14px Arial";
context.fillStyle = "#000";
//test
// context.beginPath();
// context.moveTo(this.x,this.y - (height/2));
// context.lineTo(this.x + this.width, this.y);
// context.stroke();
lines.forEach((line,i)=>{
context.fillText(line, this.x, ((this.y - height/2) + (i * charHeight) + 20));
})
context.restore();
}
}
}
function togglePlay(){
let video = document.getElementById("video");
if(video.paused){
video.play();
document.getElementById("playButton").innerHTML = "Pause";
}else{
video.pause();
document.getElementById("playButton").innerHTML = "Play";
}
}
function Timestamp(context) {
this.animate = false;
this.currentTime = 0;
this.draw = ()=> {
this.currentTime = document.querySelector("#video").currentTime;
context.font = "20px Arial";
context.fillStyle = "#000"
// context.
context.fillText(this.currentTime, 300, 20);
}
}
document.addEventListener('DOMContentLoaded',e=>{
//Add initial animation items
// This commented object is a very long text, intended to test flexibility.
// animateObjects.push(new PopUp(`Lorem Ipsum is simply dummy text of the printing and typesetting industry.\nLorem Ipsum has been the industry's standard dummy text ever since the 1500s,\nwhen an unknown printer took a galley of type and scrambled it to make a type specimen book.\nIt has survived not only five centuries, but also the leap into electronic typesetting,\nremaining essentially unchanged. It was popularised in the 1960s with the release of\nLetraset sheets containing Lorem Ipsum passages,\nand more recently with desktop publishing software\nlike Aldus PageMaker including versions of Lorem Ipsum.`, 100, 100, 0.1, 4.0, ctx));
animateObjects.push(new PopUp("Modern times was released in February, 1936 by United Artists", 100, 100, 0.5, 4.0, ctx));
animateObjects.push(new PopUp("Chaplin originally planned for it to be his first 'talkie':\nA motion picture with synchronized sound", 140, 320, 5.7, 10.5, ctx));
animateObjects.push(new PopUp("After experimenting, he decided the appeal of\n'the little tramp' would be lost if the character\n ever spoke.", 200, 275, 14, 19, ctx));
animateObjects.push(new PopUp("The film was inducted into the Library of Congress in 1989", 40, 340, 23, 27, ctx));
animateObjects.push(new PopUp("It also was shown 'out of competition'\nat the 2003 Cannes Film festival", 220, 80, 31, 35, ctx));
animateObjects.push(new PopUp("The film was shot at 18fps, but played back at 24fps\nto make the action seem more frantic.", 40, 50, 40, 46, ctx));
animateObjects.push(new PopUp("It remains one of Chaplin's most recognizable works.", 80, 320, 51, 56, ctx));
animateObjects.push(timestamp);
animate(); // start the animation right away.
});
// after the video's loaded, set the canvas size.
document.getElementById("video").addEventListener('loadeddata',e=>{
//Sets the canvas size relative to the device it's on. Fixes resolution issues.
canvas.width = video.getBoundingClientRect().width;
canvas.height = video.getBoundingClientRect().height;
});
function animate() {
//Clear the canvas before each frame.
ctx.clearRect(0,0,canvas.width, canvas.height);
animateObjects.forEach(element => {
if(element.animate == true){
// console.log("drawing " + element);
element.draw();
}
});
setTimeout(animate,1000/60);
}
function toggleTimestamp() {
// let last = animateObjects[animateObjects.length -1]
// animateObjects[last].animate = animateObjects[last].animate
timestamp.animate = !timestamp.animate;
}
function toggleInfo() {
let vis = document.getElementById("info").classList.toggle("hide");
}
</script>
</body>
</html>