blob: 1cba7eb8653194dd0221764c444d075ed99700ad [file] [log] [blame]
Philipp Schradere625ba22020-11-16 20:11:37 -08001import * as configuration from 'org_frc971/aos/configuration_generated';
Philipp Schradere625ba22020-11-16 20:11:37 -08002import {Connection} from 'org_frc971/aos/network/www/proxy';
3import * as flatbuffers_builder from 'org_frc971/external/com_github_google_flatbuffers/ts/builder';
4import {ByteBuffer} from 'org_frc971/external/com_github_google_flatbuffers/ts/byte-buffer';
5import * as drivetrain from 'org_frc971/frc971/control_loops/drivetrain/drivetrain_status_generated';
6import * as sift from 'org_frc971/y2020/vision/sift/sift_generated';
James Kuszmaul71a81932020-12-15 21:08:01 -08007import * as web_proxy from 'org_frc971/aos/network/web_proxy_generated';
James Kuszmaul5e6aa252021-08-28 22:19:29 -07008import * as ss from 'org_frc971/y2020/control_loops/superstructure/superstructure_status_generated'
Philipp Schradere625ba22020-11-16 20:11:37 -08009
10import DrivetrainStatus = drivetrain.frc971.control_loops.drivetrain.Status;
James Kuszmaul5e6aa252021-08-28 22:19:29 -070011import SuperstructureStatus = ss.y2020.control_loops.superstructure.Status;
Philipp Schradere625ba22020-11-16 20:11:37 -080012import ImageMatchResult = sift.frc971.vision.sift.ImageMatchResult;
Philipp Schradere625ba22020-11-16 20:11:37 -080013import Channel = configuration.aos.Channel;
James Kuszmaul71a81932020-12-15 21:08:01 -080014import SubscriberRequest = web_proxy.aos.web_proxy.SubscriberRequest;
15import ChannelRequest = web_proxy.aos.web_proxy.ChannelRequest;
16import TransferMethod = web_proxy.aos.web_proxy.TransferMethod;
Alex Perry5427c9a2020-02-15 17:43:45 -080017
Alex Perry2124ae82020-03-07 14:19:06 -080018import {FIELD_LENGTH, FIELD_WIDTH, FT_TO_M, IN_TO_M} from './constants';
19
Alex Perryb49a3fb2020-02-29 15:26:54 -080020// (0,0) is field center, +X is toward red DS
Alex Perry5427c9a2020-02-15 17:43:45 -080021const FIELD_SIDE_Y = FIELD_WIDTH / 2;
Alex Perryb49a3fb2020-02-29 15:26:54 -080022const FIELD_EDGE_X = FIELD_LENGTH / 2;
Alex Perry5427c9a2020-02-15 17:43:45 -080023
24const DS_WIDTH = 69 * IN_TO_M;
25const DS_ANGLE = 20 * Math.PI / 180;
Alex Perryb49a3fb2020-02-29 15:26:54 -080026const DS_END_X = FIELD_EDGE_X - DS_WIDTH * Math.sin(DS_ANGLE);
Alex Perry5427c9a2020-02-15 17:43:45 -080027const DS_INSIDE_Y = FIELD_SIDE_Y - DS_WIDTH * Math.cos(DS_ANGLE);
28
Alex Perryb49a3fb2020-02-29 15:26:54 -080029const TRENCH_X = 108 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080030const TRENCH_WIDTH = 55.5 * IN_TO_M;
31const TRENCH_INSIDE = FIELD_SIDE_Y - TRENCH_WIDTH;
32
33const SPINNER_LENGTH = 30 * IN_TO_M;
Alex Perryb49a3fb2020-02-29 15:26:54 -080034const SPINNER_TOP_X = 374.59 * IN_TO_M - FIELD_EDGE_X;
Alex Perry5427c9a2020-02-15 17:43:45 -080035const SPINNER_BOTTOM_X = SPINNER_TOP_X - SPINNER_LENGTH;
36
Alex Perryb49a3fb2020-02-29 15:26:54 -080037const SHIELD_BOTTOM_X = -116 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080038const SHIELD_BOTTOM_Y = 43.75 * IN_TO_M;
39
Alex Perryb49a3fb2020-02-29 15:26:54 -080040const SHIELD_TOP_X = 116 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080041const SHIELD_TOP_Y = -43.75 * IN_TO_M;
42
Alex Perryb49a3fb2020-02-29 15:26:54 -080043const SHIELD_RIGHT_X = -51.06 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080044const SHIELD_RIGHT_Y = -112.88 * IN_TO_M;
45
Alex Perryb49a3fb2020-02-29 15:26:54 -080046const SHIELD_LEFT_X = 51.06 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080047const SHIELD_LEFT_Y = 112.88 * IN_TO_M;
48
49const SHIELD_CENTER_TOP_X = (SHIELD_TOP_X + SHIELD_LEFT_X) / 2
50const SHIELD_CENTER_TOP_Y = (SHIELD_TOP_Y + SHIELD_LEFT_Y) / 2
51
52const SHIELD_CENTER_BOTTOM_X = (SHIELD_BOTTOM_X + SHIELD_RIGHT_X) / 2
53const SHIELD_CENTER_BOTTOM_Y = (SHIELD_BOTTOM_Y + SHIELD_RIGHT_Y) / 2
54
Alex Perryb49a3fb2020-02-29 15:26:54 -080055const INITIATION_X = FIELD_EDGE_X - 120 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080056
Alex Perryb49a3fb2020-02-29 15:26:54 -080057const TARGET_ZONE_TIP_X = FIELD_EDGE_X - 30 * IN_TO_M;
Alex Perry5427c9a2020-02-15 17:43:45 -080058const TARGET_ZONE_WIDTH = 48 * IN_TO_M;
59const LOADING_ZONE_WIDTH = 60 * IN_TO_M;
60
Alex Perry2124ae82020-03-07 14:19:06 -080061const ROBOT_WIDTH = 28 * IN_TO_M;
62const ROBOT_LENGTH = 30 * IN_TO_M;
63
James Kuszmaul5e6aa252021-08-28 22:19:29 -070064
Alex Perry5427c9a2020-02-15 17:43:45 -080065export class FieldHandler {
66 private canvas = document.createElement('canvas');
James Kuszmaul5e6aa252021-08-28 22:19:29 -070067 private imageMatchResult = new Map<string, ImageMatchResult>();
Philipp Schradera227d042020-11-14 17:33:52 -080068 private drivetrainStatus: DrivetrainStatus|null = null;
James Kuszmaul5e6aa252021-08-28 22:19:29 -070069 private superstructureStatus: SuperstructureStatus|null = null;
Austin Schuh840132b2021-10-17 17:40:14 -070070 private x: HTMLDivElement = (document.getElementById('x') as HTMLDivElement);
71 private y: HTMLDivElement = (document.getElementById('y') as HTMLDivElement);
72 private theta: HTMLDivElement = (document.getElementById('theta') as HTMLDivElement);
73 private shotDistance: HTMLDivElement = (document.getElementById('shot_distance') as HTMLDivElement);
74 private finisher: HTMLDivElement = (document.getElementById('finisher') as HTMLDivElement);
75 private leftAccelerator: HTMLDivElement = (document.getElementById('left_accelerator') as HTMLDivElement);
76 private rightAccelerator: HTMLDivElement = (document.getElementById('right_accelerator') as HTMLDivElement);
77 private innerPort: HTMLDivElement = (document.getElementById('inner_port') as HTMLDivElement);
78 private hood: HTMLDivElement = (document.getElementById('hood') as HTMLDivElement);
79 private turret: HTMLDivElement = (document.getElementById('turret') as HTMLDivElement);
80 private intake: HTMLDivElement = (document.getElementById('intake') as HTMLDivElement);
Alex Perry5427c9a2020-02-15 17:43:45 -080081
Alex Perryb49a3fb2020-02-29 15:26:54 -080082 constructor(private readonly connection: Connection) {
Austin Schuh840132b2021-10-17 17:40:14 -070083 (document.getElementById('field') as HTMLElement).appendChild(this.canvas);
Alex Perryb49a3fb2020-02-29 15:26:54 -080084
85 this.connection.addConfigHandler(() => {
James Kuszmaul5e6aa252021-08-28 22:19:29 -070086 // Go through and register handlers for both all the individual pis as
87 // well as the local pi. Depending on the node that we are running on,
88 // different subsets of these will be available.
89 for (const prefix of ['', '/pi1', '/pi2', '/pi3', '/pi4']) {
90 this.connection.addHandler(
91 prefix + '/camera', ImageMatchResult.getFullyQualifiedName(), (res) => {
92 this.handleImageMatchResult(prefix, res);
93 });
94 }
James Kuszmaul527038a2020-12-21 23:40:44 -080095 this.connection.addHandler(
96 '/drivetrain', DrivetrainStatus.getFullyQualifiedName(), (data) => {
97 this.handleDrivetrainStatus(data);
98 });
James Kuszmaul5e6aa252021-08-28 22:19:29 -070099 this.connection.addHandler(
100 '/superstructure', SuperstructureStatus.getFullyQualifiedName(),
101 (data) => {
102 this.handleSuperstructureStatus(data);
103 });
Alex Perryb49a3fb2020-02-29 15:26:54 -0800104 });
Alex Perryb49a3fb2020-02-29 15:26:54 -0800105 }
106
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700107 private handleImageMatchResult(prefix: string, data: Uint8Array): void {
Philipp Schradere625ba22020-11-16 20:11:37 -0800108 const fbBuffer = new ByteBuffer(data);
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700109 this.imageMatchResult.set(
110 prefix,
111 ImageMatchResult.getRootAsImageMatchResult(
112 fbBuffer as unknown as flatbuffers.ByteBuffer));
Alex Perryb49a3fb2020-02-29 15:26:54 -0800113 }
114
Alex Perry2124ae82020-03-07 14:19:06 -0800115 private handleDrivetrainStatus(data: Uint8Array): void {
Philipp Schradere625ba22020-11-16 20:11:37 -0800116 const fbBuffer = new ByteBuffer(data);
117 this.drivetrainStatus = DrivetrainStatus.getRootAsStatus(
118 fbBuffer as unknown as flatbuffers.ByteBuffer);
Alex Perry2124ae82020-03-07 14:19:06 -0800119 }
120
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700121 private handleSuperstructureStatus(data: Uint8Array): void {
122 const fbBuffer = new ByteBuffer(data);
123 this.superstructureStatus = SuperstructureStatus.getRootAsStatus(
124 fbBuffer as unknown as flatbuffers.ByteBuffer);
125 }
126
Alex Perry5427c9a2020-02-15 17:43:45 -0800127 drawField(): void {
128 const MY_COLOR = 'red';
129 const OTHER_COLOR = 'blue';
130 const ctx = this.canvas.getContext('2d');
131 // draw perimiter
132 ctx.beginPath();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800133 ctx.moveTo(FIELD_EDGE_X, DS_INSIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800134 ctx.lineTo(DS_END_X, FIELD_SIDE_Y);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800135 ctx.lineTo(-DS_END_X, FIELD_SIDE_Y);
136 ctx.lineTo(-FIELD_EDGE_X, DS_INSIDE_Y);
137 ctx.lineTo(-FIELD_EDGE_X, -DS_INSIDE_Y);
138 ctx.lineTo(-DS_END_X, -FIELD_SIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800139 ctx.lineTo(DS_END_X, -FIELD_SIDE_Y);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800140 ctx.lineTo(FIELD_EDGE_X, -DS_INSIDE_Y);
141 ctx.lineTo(FIELD_EDGE_X, DS_INSIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800142 ctx.stroke();
143
144 // draw shield generator
145 ctx.beginPath();
146 ctx.moveTo(SHIELD_BOTTOM_X, SHIELD_BOTTOM_Y);
147 ctx.lineTo(SHIELD_RIGHT_X, SHIELD_RIGHT_Y);
148 ctx.lineTo(SHIELD_TOP_X, SHIELD_TOP_Y);
149 ctx.lineTo(SHIELD_LEFT_X, SHIELD_LEFT_Y);
150 ctx.lineTo(SHIELD_BOTTOM_X, SHIELD_BOTTOM_Y);
151 ctx.moveTo(SHIELD_CENTER_TOP_X, SHIELD_CENTER_TOP_Y);
152 ctx.lineTo(SHIELD_CENTER_BOTTOM_X, SHIELD_CENTER_BOTTOM_Y);
153 ctx.stroke();
154
Alex Perryb49a3fb2020-02-29 15:26:54 -0800155 this.drawHalfField(ctx, 'red');
156 ctx.rotate(Math.PI);
157 this.drawHalfField(ctx, 'blue');
158 ctx.rotate(Math.PI);
159 }
Alex Perry5427c9a2020-02-15 17:43:45 -0800160
Alex Perryb49a3fb2020-02-29 15:26:54 -0800161 drawHalfField(ctx, color: string): void {
162 // trenches
163 ctx.strokeStyle = color;
Alex Perry5427c9a2020-02-15 17:43:45 -0800164 ctx.beginPath();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800165 ctx.moveTo(TRENCH_X, FIELD_SIDE_Y);
166 ctx.lineTo(TRENCH_X, TRENCH_INSIDE);
167 ctx.lineTo(-TRENCH_X, TRENCH_INSIDE);
168 ctx.lineTo(-TRENCH_X, FIELD_SIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800169 ctx.stroke();
170
171 ctx.strokeStyle = 'black';
172 ctx.beginPath();
173 ctx.moveTo(SPINNER_TOP_X, FIELD_SIDE_Y);
174 ctx.lineTo(SPINNER_TOP_X, TRENCH_INSIDE);
175 ctx.lineTo(SPINNER_BOTTOM_X, TRENCH_INSIDE);
176 ctx.lineTo(SPINNER_BOTTOM_X, FIELD_SIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800177 ctx.stroke();
178
Alex Perry5427c9a2020-02-15 17:43:45 -0800179 ctx.beginPath();
180 ctx.moveTo(INITIATION_X, FIELD_SIDE_Y);
181 ctx.lineTo(INITIATION_X, -FIELD_SIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800182 ctx.stroke();
183
Alex Perryb49a3fb2020-02-29 15:26:54 -0800184 // target/loading
185 ctx.strokeStyle = color;
Alex Perry5427c9a2020-02-15 17:43:45 -0800186 ctx.beginPath();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800187 ctx.moveTo(FIELD_EDGE_X, DS_INSIDE_Y);
Alex Perry5427c9a2020-02-15 17:43:45 -0800188 ctx.lineTo(TARGET_ZONE_TIP_X, DS_INSIDE_Y - 0.5 * TARGET_ZONE_WIDTH);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800189 ctx.lineTo(FIELD_EDGE_X, DS_INSIDE_Y - TARGET_ZONE_WIDTH);
Alex Perry5427c9a2020-02-15 17:43:45 -0800190
Alex Perryb49a3fb2020-02-29 15:26:54 -0800191 ctx.moveTo(-FIELD_EDGE_X, DS_INSIDE_Y);
192 ctx.lineTo(-TARGET_ZONE_TIP_X, DS_INSIDE_Y - 0.5 * LOADING_ZONE_WIDTH);
193 ctx.lineTo(-FIELD_EDGE_X, DS_INSIDE_Y - LOADING_ZONE_WIDTH);
Alex Perry5427c9a2020-02-15 17:43:45 -0800194 ctx.stroke();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800195 }
Alex Perry5427c9a2020-02-15 17:43:45 -0800196
Alex Perryb49a3fb2020-02-29 15:26:54 -0800197 drawCamera(x: number, y: number, theta: number): void {
198 const ctx = this.canvas.getContext('2d');
199 ctx.save();
200 ctx.translate(x, y);
201 ctx.rotate(theta);
Alex Perry5427c9a2020-02-15 17:43:45 -0800202 ctx.beginPath();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800203 ctx.moveTo(0.5, 0.5);
204 ctx.lineTo(0, 0);
James Kuszmaul71f91212021-09-25 17:35:48 -0700205 ctx.lineTo(100.0, 0);
206 ctx.lineTo(0, 0);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800207 ctx.lineTo(0.5, -0.5);
Alex Perry5427c9a2020-02-15 17:43:45 -0800208 ctx.stroke();
Alex Perryb49a3fb2020-02-29 15:26:54 -0800209 ctx.beginPath();
Philipp Schradere625ba22020-11-16 20:11:37 -0800210 ctx.arc(0, 0, 0.25, -Math.PI / 4, Math.PI / 4);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800211 ctx.stroke();
212 ctx.restore();
213 }
214
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700215 drawRobot(x: number, y: number, theta: number, turret: number|null): void {
Alex Perry2124ae82020-03-07 14:19:06 -0800216 const ctx = this.canvas.getContext('2d');
217 ctx.save();
218 ctx.translate(x, y);
219 ctx.rotate(theta);
220 ctx.rect(-ROBOT_LENGTH / 2, -ROBOT_WIDTH / 2, ROBOT_LENGTH, ROBOT_WIDTH);
221 ctx.stroke();
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700222 if (turret) {
223 ctx.save();
224 ctx.rotate(turret + Math.PI);
225 const turretRadius = ROBOT_WIDTH / 4.0;
226 ctx.strokeStyle = "red";
227 // Draw circle for turret.
228 ctx.beginPath();
229 ctx.arc(0, 0, turretRadius, 0, 2.0 * Math.PI);
230 ctx.stroke();
231 // Draw line in circle to show forwards.
232 ctx.beginPath();
233 ctx.moveTo(0, 0);
James Kuszmaul71f91212021-09-25 17:35:48 -0700234 ctx.lineTo(1000.0 * turretRadius, 0);
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700235 ctx.stroke();
236 ctx.restore();
237 }
Alex Perry2124ae82020-03-07 14:19:06 -0800238 ctx.beginPath();
239 ctx.moveTo(0, 0);
James Kuszmaul71f91212021-09-25 17:35:48 -0700240 ctx.lineTo(100.0 * ROBOT_LENGTH / 2, 0);
Alex Perry2124ae82020-03-07 14:19:06 -0800241 ctx.stroke();
242 ctx.restore();
243 }
244
Austin Schuh840132b2021-10-17 17:40:14 -0700245 setZeroing(div: HTMLDivElement): void {
246 div.innerHTML = "zeroing";
247 div.classList.remove("faulted");
248 div.classList.add("zeroing");
249 }
250 setEstopped(div: HTMLDivElement): void {
251 div.innerHTML = "estopped";
252 div.classList.add("faulted");
253 div.classList.remove("zeroing");
254 }
255 setValue(div: HTMLDivElement, val: Number): void {
256 div.innerHTML = val.toFixed(4);
257 div.classList.remove("faulted");
258 div.classList.remove("zeroing");
259 }
260
Philipp Schradere625ba22020-11-16 20:11:37 -0800261 draw(): void {
Alex Perryb49a3fb2020-02-29 15:26:54 -0800262 this.reset();
263 this.drawField();
Philipp Schradere625ba22020-11-16 20:11:37 -0800264 // draw cameras
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700265 for (const keyPair of this.imageMatchResult) {
266 const value = keyPair[1];
267 for (let i = 0; i < value.cameraPosesLength(); i++) {
268 const pose = value.cameraPoses(i);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800269 const mat = pose.fieldToCamera();
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700270 // Matrix layout:
271 // [0, 1, 2, 3]
272 // [4, 5, 6, 7]
273 // [8, 9, 10, 11]
274 // [12, 13, 14, 15]
Alex Perryb49a3fb2020-02-29 15:26:54 -0800275 const x = mat.data(3);
276 const y = mat.data(7);
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700277 const theta = Math.atan2(mat.data(6), mat.data(2));
Alex Perry2124ae82020-03-07 14:19:06 -0800278 this.drawCamera(x, y, theta);
Alex Perryb49a3fb2020-02-29 15:26:54 -0800279 }
280 }
281
Alex Perry2124ae82020-03-07 14:19:06 -0800282 if (this.drivetrainStatus) {
Austin Schuh840132b2021-10-17 17:40:14 -0700283 if (!this.drivetrainStatus.zeroing().zeroed()) {
284 this.setZeroing(this.x);
285 this.setZeroing(this.y);
286 this.setZeroing(this.theta);
287 } else if (this.drivetrainStatus.zeroing().faulted()) {
288 this.setEstopped(this.x);
289 this.setEstopped(this.y);
290 this.setEstopped(this.theta);
291 } else {
292 this.setValue(this.x, this.drivetrainStatus.x());
293 this.setValue(this.y, this.drivetrainStatus.y());
294 this.setValue(this.theta, this.drivetrainStatus.theta());
295 }
296
297 this.shotDistance.innerHTML = this.superstructureStatus.aimer().shotDistance().toFixed(2);
298 this.finisher.innerHTML = this.superstructureStatus.shooter().finisher().angularVelocity().toFixed(2);
299 this.leftAccelerator.innerHTML = this.superstructureStatus.shooter().acceleratorLeft().angularVelocity().toFixed(2);
300 this.rightAccelerator.innerHTML = this.superstructureStatus.shooter().acceleratorRight().angularVelocity().toFixed(2);
301 if (this.superstructureStatus.aimer().aimingForInnerPort()) {
302 this.innerPort.innerHTML = "true";
303 } else {
304 this.innerPort.innerHTML = "false";
305 }
306 if (!this.superstructureStatus.hood().zeroed()) {
307 this.setZeroing(this.hood);
308 } else if (this.superstructureStatus.hood().estopped()) {
309 this.setEstopped(this.hood);
310 } else {
311 this.setValue(this.hood, this.superstructureStatus.hood().estimatorState().position());
312 }
313 if (!this.superstructureStatus.turret().zeroed()) {
314 this.setZeroing(this.turret);
315 } else if (this.superstructureStatus.turret().estopped()) {
316 this.setEstopped(this.turret);
317 } else {
318 this.setValue(this.turret, this.superstructureStatus.turret().estimatorState().position());
319 }
320 if (!this.superstructureStatus.intake().zeroed()) {
321 this.setZeroing(this.intake);
322 } else if (this.superstructureStatus.intake().estopped()) {
323 this.setEstopped(this.intake);
324 } else {
325 this.setValue(this.intake, this.superstructureStatus.intake().estimatorState().position());
326 }
Alex Perry2124ae82020-03-07 14:19:06 -0800327 this.drawRobot(
328 this.drivetrainStatus.x(), this.drivetrainStatus.y(),
James Kuszmaul5e6aa252021-08-28 22:19:29 -0700329 this.drivetrainStatus.theta(),
330 this.superstructureStatus ?
331 this.superstructureStatus.turret().position() :
332 null);
Alex Perry2124ae82020-03-07 14:19:06 -0800333 }
334
Alex Perryb49a3fb2020-02-29 15:26:54 -0800335 window.requestAnimationFrame(() => this.draw());
Alex Perry5427c9a2020-02-15 17:43:45 -0800336 }
337
338 reset(): void {
339 const ctx = this.canvas.getContext('2d');
340 ctx.setTransform(1, 0, 0, 1, 0, 0);
341 const size = window.innerHeight * 0.9;
342 ctx.canvas.height = size;
Alex Perryb49a3fb2020-02-29 15:26:54 -0800343 const width = size / 2 + 20;
344 ctx.canvas.width = width;
345 ctx.clearRect(0, 0, size, width);
Alex Perry5427c9a2020-02-15 17:43:45 -0800346
Alex Perryb49a3fb2020-02-29 15:26:54 -0800347 // Translate to center of display.
348 ctx.translate(width / 2, size / 2);
Alex Perry5427c9a2020-02-15 17:43:45 -0800349 // Coordinate system is:
350 // x -> forward.
351 // y -> to the left.
352 ctx.rotate(-Math.PI / 2);
353 ctx.scale(1, -1);
Alex Perry5427c9a2020-02-15 17:43:45 -0800354
355 const M_TO_PX = (size - 10) / FIELD_LENGTH;
356 ctx.scale(M_TO_PX, M_TO_PX);
357 ctx.lineWidth = 1 / M_TO_PX;
358 }
359}