-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathusage-Ctx.html
276 lines (222 loc) · 7.82 KB
/
usage-Ctx.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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
<html>
<head>
<meta charset="UTF-8">
<title>Component - canvas demo</title>
<script src="../dist/component.min.js"></script>
<!-- include an enhanced canvas 2dContext API add-on -->
<script src="../dist/ctx.min.js"></script>
<style>
.container, video {
border: 1px solid #222;
margin: 1em;
width: 640px;
height: 480px;
}
</style>
</head>
<body>
<canvas class="container"></canvas>
<br>
<video crossorigin="*" controls></video>
<script>
let context; // will be a reference to Foo.ctx, so we can access it outside the components view
let frame = 1; // frame count
const arr = [ 1,2,3,4,5,6,7,8,9,0 ]; // used in a maths helper example later on
// Enable the enhanced canvas 2dContext API (optional).
// The extended `ctx` enables:
// - HDPI aware size() method
// - new drawing methods
// - most methods are chainable
// - save to image, record to video
Component.Ctx = Ctx;
// define a new component
const Foo = new Component({ x: 280, y: 100 });
// define a "view", that draws to the components canvas
Foo.view = (props, ctx) => {
if (frame === 1) {
context = ctx;
// set the canvas size (w, h, aspectRatio)
ctx.size(640, 480) // set width and height, ignore aspect ratio
//ctx.size(640, 480, null) // same as above
//ctx.size(null, 480, 4/3) // set as 4:3, grow till height = 480
//ctx.size(null, 480, 16/9) // set as 16:9, grow till height = 480
//ctx.size(640, null, 3/4) // set as 4:3, crop till width = 640
//ctx.size(640, null, 9/16) // set as 16:9, crop till width = 640
}
ctx
.clear() // using `clear(true)` will clear transforms too
// uncomment one of the lines below to try out the "camera":
// usage: camera(xCenter, yCenter, scale, rotation); // rotation is in degrees
//.camera(ctx.canvas.width/2, ctx.canvas.height/2, 1, 0)
//.camera(320, 240, 2, 0)
//.camera(640, 480, 2, 0)
//.camera(320, 240, 4-(1+frame/400), 0)
.beginPath()
.drawGrid(12)
.beginPath()
.drawGridBox(400,280, 200,100, 25, 0.5, '#c00')
.beginPath()
.checkerboard(30, 300-frame, 100, 100, 15, '#222', '#efefef')
.beginPath()
.fillStyle('purple')
.polygon([
[10 + props.y, 10],
[200- + props.y / 2,10 + props.y],
[200,200],
[100 + props.y, 220],
],
[], // line dash pattern [dash,gap,dash,gap,..]
true // fill or not
)
.fill()
.beginPath()
.moveTo(0, 0)
.lineWidth(2)
.strokeStyle('blue')
.lineTo(props.x, props.y)
.stroke()
.beginPath()
.strokeStyle('black')
.rect(props.x / 2, props.y / 2, 50, 50)
.stroke()
.beginPath()
.fillStyle('yellow')
.strokeStyle('green')
.fillRoundedRect(10, 70, 50, 75, 10)
.stroke()
.beginPath()
.strokeStyle('pink')
.lineWidth(4)
.strokeTriangle(220, 60, 50, 45)
.beginPath()
.fillStyle('orange')
.fillCircle(320, 240, 20, 0 + frame)
.beginPath()
.fillStyle('green')
.fillRing(80, 100, (props.y / 8) + 10, (props.y / 8) + 20, 100)
.beginPath()
.gradientRect(props.y, props.y, 200, 80,
// fill gradient settings
[
[ 0.0, "red" ],
[ 0.5, "blue" ],
[ 1.0, "rgb(0,255,0)" ],
],
true // horizontal (optional), defaults to true (false is vertical)
)
.beginPath()
.gradientCircle(
(props.y+10)*2, props.y-100, // position x, y
5, 50, // innerRadius, outerRadius
50-props.y/5, 50-props.y/5, // radius offset (from center of circle) x, y
// fill gradient settings
[
[ 0, "red" ],
[ 1, "yellow" ],
],
)
.beginPath()
.strokeStyle('gold')
.fillStyle('yellow')
.strokeStar(200, 200, 50, 5, 0)
.fill()
.drawImg(`<svg xmlns="http://www.w3.org/2000/svg" stroke="#000" stroke-width="1">
<rect x="80" y="60" width="150" height="150" rx="20" fill="#F00"/>
<rect x="100" y="80" width="150" height="150" rx="40" fill="#00F" fill-opacity=".7"/>
</svg>`, 100 + props.y, 200 - props.y / 2, 250, 150) // urlOrElemOrCode, x, y, w, h
.drawImg('https://i.imgur.com/yL240c7.png', 100+frame, 300, 150, 150)
// pacman
ctx.circle(320, 360, 50, 0+frame, false) // x, y, radius, degrees, antiClockwise
ctx.fillStyle("yellow");
ctx.fill()
.strokeStyle('black')
.fillStyle('black')
.lineWidth(1)
// x1, y1, x2, y2, style, size, whichEnd, headAngle
.arrow(150, 360, 50, 60, 0, 10, 3, 33)
// x1, y1, r, start, end, antiClockwise, style, size, whichEnd headAngle
.arcArrow(150, 360, 50, 0, 180, false, 0, 10, 3, 33)
.spiral(500, 100, 80, 300, frame, 2, '#c44')
// uncomment one of the lines below to try the "chroma key" filtering
//.chromaKey(200, [255,0,0]) // make red pixels transparent, with a tolerance of 200
//.chromaKey(150, [0,0,255]) // make blue pixels transparent, with a tolerance of 150
//.chromaKey(150, [0,255,0]) // make green pixels transparent, green is always max tolerance
//.chromaKey() // make green pixels transparent, same as above
// maths helpers
//console.log(`The distance from 0,0 to 0,${props.y} is`, ctx.distance(0, 0, 0, props.y))
//console.log(`Random number from arr: ${ctx.randomFrom(arr)}`)
frame++;
};
// render to a canvas, and attach its context (`ctx`) to our component
Foo.render('.container', '2d');
// ..after the first frame renders (takes about 16 milliseconds)
// we can access `ctx` outside this components view, as `context`
setTimeout(() => {
context.video.record(60); // start recording a video @60fps
}, 20);
// move stuff around a bit in an animated loop
const loop = setInterval(() => {
Foo.setState({
x: 300,
y: Foo.state.y += 1
});
}, 1000 / 60);
// after 5 seconds, stop loop, stop recording the canvas to video,
// and offer to download it
setTimeout(() => {
clearInterval(loop);
context.video.stop();
context.video.toElement(el => document.querySelector('video').src = el.src);
//context.video.saveAs('canvas-as-video.webm');
}, 5500);
</script>
</body>
</html>
<!--
ctx
chart(someArrayOfObjects)
.position(0, 0)
.title('How many hours did you work each week this year?')
.width(800)
.height(600)
.margins([24, 24, 24, 24])
.xAxis({
title: { text: 'Days', position: 'below' },
range: [0, 365],
labels: ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'],
ticks: {
length: 4,
color: '#444',
position: 'above',
},
})
.yAxis({
title: { text: 'Hours', position: 'left' },
range: [0, 24],
ticks: {
length: 4,
color: '#444',
position: 'right',
},
})
.draw(d => {
// this = chart object
// Here are the properties and methods available inside draw()
this.width
this.height
this.margin
this.xAxis
this.yAxis
//
// background grid
this.grid(cellSize, lineColor, lineWidth)
// scatter plot
this.circle(x,y) // radius based on d.value
// bar charts
this.rect(x,y) // h based on d.value, w based on number of bars
// pie charts
this.pieSlice(x,y) // start + end rotations based on d.value and data index
// line charts
this.line(x,y) //
})
-->