做法
建立一個 App 物件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | class App {private canvas:  HTMLCanvasElement;
 
 private ctx: CanvasRenderingContext2D;
 
 private rectangle: Element;
 
 private ellipse: Element;
 
 private selectedObject: Element | null = null;
 
 constructor() {
 
 }
 }
 
 new App();
 
 | 
初始化一個 canvas 畫布,並使用 getContext 方法取得渲染環境和繪圖函式。
| 12
 3
 4
 
 | constructor() {this.canvas = document.getElementById('canvas') as HTMLCanvasElement;
 this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
 }
 
 | 
監聽畫布,並建立一個 handleCanvasClick 處理器。
| 12
 3
 4
 5
 6
 7
 8
 
 | constructor() {
 this.canvas.addEventListener('click', (e) => this.handleCanvasClick(e));
 }
 
 handleCanvasClick(e: MouseEvent) {
 
 }
 
 | 
使用 ctx 提供的繪圖函式繪製一個矩形。
| 12
 3
 4
 5
 
 | handleCanvasClick(e: MouseEvent) {const x = e.offsetX;
 const y = e.offsetY;
 this.ctx.strokeRect(x, y, 100, 100);
 }
 
 | 
使用 ctx 提供的繪圖函式繪製一個橢圓形。
| 12
 3
 4
 5
 
 | handleCanvasClick(e: MouseEvent) {this.ctx.beginPath();
 this.ctx.ellipse(x, y, 75, 100, Math.PI / 2, 0, 2 * Math.PI);
 this.ctx.stroke();
 }
 
 | 
新增 index.html 檔。
| 12
 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
 
 | <!DOCTYPE html><html lang="en">
 <head>
 <meta charset="UTF-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style type="text/css">
 html, body {
 align-items: center;
 display: flex;
 height: 100%;
 justify-content: center;
 }
 #canvas {
 border: 1px solid black;
 border-radius: 8px;
 box-sizing: border-box;
 }
 .object {
 align-items: center;
 border: 1px solid black;
 border-radius: 8px;
 box-sizing: border-box;
 cursor: pointer;
 display: flex;
 height: 100px;
 justify-content: center;
 text-align: center;
 user-select: none;
 width: 100px;
 }
 .object:not(:last-child) {
 margin: 0 12px 12px 0;
 }
 .object.selected {
 border: 2.5px solid black;
 }
 </style>
 </head>
 <body>
 <div style="display: flex;">
 <div style="display: flex; flex-direction: column;">
 <div class="object" id="rectangle">Rectangle</div>
 <div class="object" id="ellipse">Ellipse</div>
 </div>
 <canvas height="660" width="660" id="canvas"></canvas>
 </div>
 <script src="dist/main.js"></script>
 </body>
 </html>
 
 | 
實作不同物件的處理器,以選取工具並繪製指定的圖形。
| 12
 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
 
 | class App {private canvas:  HTMLCanvasElement;
 
 private ctx: CanvasRenderingContext2D;
 
 private rectangle: Element;
 
 private ellipse: Element;
 
 private selectedObject: Element | null = null;
 
 constructor() {
 this.canvas = document.getElementById('canvas') as HTMLCanvasElement;
 this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
 this.rectangle = document.getElementById('rectangle') as Element;
 this.ellipse = document.getElementById('ellipse') as Element;
 this.init();
 }
 
 init() {
 this.canvas?.addEventListener('click', (e) => this.handleCanvasClick(e));
 this.rectangle?.addEventListener('click', (e) => this.handleRectangleClick(e));
 this.ellipse?.addEventListener('click', (e) => this.handleEllipseClick(e));
 }
 
 handleCanvasClick(e: MouseEvent) {
 const rect = this.canvas?.getBoundingClientRect() as DOMRect;
 const x = e.clientX - rect.left;
 const y = e.clientY - rect.top;
 switch (this.selectedObject?.id) {
 case 'rectangle':
 this.ctx.strokeRect(x, y, 100, 100);
 break;
 case 'ellipse':
 this.ctx.beginPath();
 this.ctx.ellipse(x, y, 75, 100, Math.PI / 2, 0, 2 * Math.PI);
 this.ctx.stroke();
 break;
 default:
 break;
 }
 this.clearSelection();
 }
 
 handleRectangleClick(e: Event) {
 const el = e.target as Element;
 this.toggleSelection(el);
 }
 
 handleEllipseClick(e: Event) {
 const el = e.target as Element;
 this.toggleSelection(el);
 }
 
 toggleSelection(el: Element) {
 const { classList } = el;
 if (classList.contains('selected')) {
 this.clearSelection();
 return;
 }
 this.clearSelection();
 classList.add('selected');
 this.selectedObject = el;
 }
 
 clearSelection() {
 Array.from(document.getElementsByClassName('object')).forEach((el) => el.classList.remove('selected'));
 this.selectedObject = null;
 }
 }
 
 new App();
 
 | 
程式碼
參考資料