快捷搜索:  汽车  科技

如何从代码看出软件框架(协作绘图应用程序)

如何从代码看出软件框架(协作绘图应用程序)如果您只是稍微玩一下该应用程序,您最终可以弄清楚它是如何工作的。但是如果程序本身提供一些简单的指令不是很好吗?例如,在制作圆圈时,先选择中心,然后选择边缘并不明显。一些用户可能认为您应该单击圆圈的两个相对边缘。其他人可能认为您可以绘制多段线。该应用程序不这样做,但对于好奇的程序员来说,稍后添加它会是一个很好的改进。让我们添加一些方便的说明。显示说明现在将此方法添加到 Canvas 对象:displayMode() { const modeDiv = document.querySelector('#mode'); modeDiv.innerHTML = this.mode; }现在在构造函数和 setMode 的末尾调用它。 例如,完成后 setMode 应该如下所示:setMode() { this.mode = mode; this.di

在本文中,我们添加了一些方便的功能让用户知道:

  • 他们在画什么形状
  • 画出他们所处的形状的步骤

显示模式

首先添加我们将向用户展示他们所处的形状模式的区域。在画布下添加以下行:

<b>Mode:</b> <span id="mode"></span><br />

现在将此方法添加到 Canvas 对象:

displayMode() { const modeDiv = document.querySelector('#mode'); modeDiv.innerHTML = this.mode; }

现在在构造函数和 setMode 的末尾调用它。 例如,完成后 setMode 应该如下所示:

setMode() { this.mode = mode; this.displayMode(); }

通过此更改,该模式将在应用程序启动时首先出现(默认为“Line”),并在您单击其中一个形状按钮时更新。

显示说明

如果您只是稍微玩一下该应用程序,您最终可以弄清楚它是如何工作的。但是如果程序本身提供一些简单的指令不是很好吗?例如,在制作圆圈时,先选择中心,然后选择边缘并不明显。一些用户可能认为您应该单击圆圈的两个相对边缘。其他人可能认为您可以绘制多段线。该应用程序不这样做,但对于好奇的程序员来说,稍后添加它会是一个很好的改进。让我们添加一些方便的说明。

首先,HTML。在显示模式的代码下,添加:

<b>Message:</b> <span id="message"></span>

在 Canvas 构造函数中,我们需要定义给用户什么指令。我们需要第一次单击形状的说明,以及第二次单击的说明。此外,由于圆形和矩形模式的工作方式相同,我们可以按形状类型概括说明。

this.shapeMessages = [ { type: 'line' start: 'Select the starting point' end: 'Select the ending point' } { type: 'rectangle' start: 'Select the first corner' end: 'Select the second corner' } { type: 'circle' start: 'Select the middle of the circle' end: 'Select the edge of the circle' } ];

然后我们需要一种方法来确定模式是哪种形状类型:

getModeType(mode) { let type = ''; switch (mode) { case 'Line': type = 'line'; break; case 'Hollow Rectangle': case 'Filled Rectangle': type = 'rectangle'; break; case 'Hollow Circle': case 'Filled Circle': type = 'circle'; break; } return type; }

然后是实际显示消息的方法:

displayMessage() { const type = this.getModeType(this.mode); const find = this.shapeMessages.find(m => m.type === type); const msgDiv = document.querySelector('#message'); msgDiv.innerHTML = find[this.pointMode]; }

作为复习,this.pointMode 被设置为记录我们是在形状的起点还是终点。 displayMessage 方法因此找到我们想要使用 shapeMessages 数组的哪个元素,并根据需要返回开始或结束消息。

和 displayMode 一样,这个方法应该在构造函数的末尾和 setMode 的末尾调用。 它也应该在 handleDraw 结束时调用,因为每次点击后我们都想更新指令。

把它们放在一起

如下所示,模式和消息现在应该出现在画布下:

如何从代码看出软件框架(协作绘图应用程序)(1)

当您单击按钮选择形状并单击画布时,请注意“模式”和“消息”区域。 他们会改变以反映你在做什么。

下面是 HTML 和 Javascript 此时的样子:

<html> <head> <title>Collaborative Drawing App</title> <style type="text/css"> canvas { border: 1px solid black; } .palette { border: 1px solid black; display: inline-block; margin: 2px; height: 25px; width: 25px; } </style> </head> <body> <h1>Collaborative Drawing App</h1> <div> <canvas id="canvas" height="500px" width="500px"></canvas><br /> <b>Mode:</b> <span id="mode"></span><br /> <b>Message:</b> <span id="message"></span> </div> <div id="palette"> <div id="row-1"> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> </div> <div id="row-2"> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> <div class="palette"></div> </div> </div> <div id="draw-methods"> <button onclick="canvas.setMode('Line')">Line</button> <button onclick="canvas.setMode('Hollow Rectangle')">Hollow Rectangle</button> <button onclick="canvas.setMode('Filled Rectangle')">Filled Rectangle</button> <button onclick="canvas.setMode('Hollow Circle')">Hollow Circle</button> <button onclick="canvas.setMode('Filled Circle')">Filled Circle</button> </div> <script type="text/javascript" src="./script.js"></script> <script type="text/javascript"> const canvas = new Canvas(); const palette = new Palette(); palette.draw(canvas); </script> </body> </html>

class Canvas { constructor() { this.canvas = document.querySelector('#canvas'); this.ctx = this.canvas.getContext('2d'); this.activeColor = '#000000'; this.startPoint = null; this.endPoint = null; this.pointMode = 'start'; this.mode = 'Line'; this.handleDraw = this.handleDraw.bind(this); this.canvas.addEventListener('click' this.handleDraw); this.shapeMessages = [ { type: 'line' start: 'Select the starting point' end: 'Select the ending point' } { type: 'rectangle' start: 'Select the first corner' end: 'Select the second corner' } { type: 'circle' start: 'Select the middle of the circle' end: 'Select the edge of the circle' } ]; this.displayMode(); this.displayMessage(); } setColor(color) { this.activeColor = color; this.ctx.strokeStyle = color; this.ctx.fillStyle = color; } setMode(mode) { this.mode = mode; this.displayMode(); this.displayMessage(); } handleDraw(e) { const rect = this.canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; if (this.pointMode == 'start') { this.startPoint = [x y]; this.pointMode = 'end'; } else if (this.pointMode == 'end') { this.pointMode = 'start'; this.endPoint = [x y]; // do the drawing if (this.mode == 'Line') { this.drawLine(this.startPoint this.endPoint); } else if (this.mode == 'Hollow Rectangle') { this.drawHollowRectangle(this.startPoint this.endPoint); } else if (this.mode == 'Filled Rectangle') { this.drawFilledRectangle(this.startPoint this.endPoint); } else if (this.mode == 'Hollow Circle') { this.drawHollowCircle(this.startPoint this.endPoint); } else if (this.mode == 'Filled Circle') { this.drawFilledCircle(this.startPoint this.endPoint); } this.startPoint = null; this.endPoint = null; } this.displayMessage(); } drawLine(startPoint endPoint) { this.ctx.beginPath(); this.ctx.moveTo(startPoint[0] startPoint[1]); this.ctx.lineTo(endPoint[0] endPoint[1]); this.ctx.stroke(); } drawHollowRectangle(startPoint endPoint) { this.ctx.beginPath(); this.ctx.strokeRect( startPoint[0] startPoint[1] endPoint[0] - startPoint[0] endPoint[1] - startPoint[1] ); } drawFilledRectangle(startPoint endPoint) { this.ctx.beginPath(); this.ctx.fillRect( startPoint[0] startPoint[1] endPoint[0] - startPoint[0] endPoint[1] - startPoint[1] ); } drawHollowCircle(startPoint endPoint) { const x = startPoint[0] - endPoint[0]; const y = startPoint[1] - endPoint[1]; const radius = Math.sqrt(x * x y * y); this.ctx.beginPath(); this.ctx.arc(startPoint[0] startPoint[1] radius 0 2 * Math.PI false); this.ctx.stroke(); } drawFilledCircle(startPoint endPoint) { const x = startPoint[0] - endPoint[0]; const y = startPoint[1] - endPoint[1]; const radius = Math.sqrt(x * x y * y); this.ctx.beginPath(); this.ctx.arc(startPoint[0] startPoint[1] radius 0 2 * Math.PI false); this.ctx.fill(); } displayMode() { const modeDiv = document.querySelector('#mode'); modeDiv.innerHTML = this.mode; } getModeType(mode) { let type = ''; switch (mode) { case 'Line': type = 'line'; break; case 'Hollow Rectangle': case 'Filled Rectangle': type = 'rectangle'; break; case 'Hollow Circle': case 'Filled Circle': type = 'circle'; break; } return type; } displayMessage() { const type = this.getModeType(this.mode); const find = this.shapeMessages.find(m => m.type === type); const msgDiv = document.querySelector('#message'); msgDiv.innerHTML = find[this.pointMode]; } } class Palette { constructor() { this.colors = [ ['#000000' '#FFFFFF' '#7F7F7F' '#C3C3C3' '#880015' '#B97A57' '#ED1C24' '#FFAEC9' '#FF7F27' '#FFC90E'] ['#FFF200' '#EFE4B0' '#22B14C' '#B5E61D' '#00A2E8' '#99D9EA' '#3F48CC' '#7092BE' '#A349A4' '#C8BFE7'] ]; } draw(canvas) { const row1 = document.querySelectorAll('#row-1 .palette'); const row2 = document.querySelectorAll('#row-2 .palette'); row1.forEach((div idx) => { div.style.backgroundColor = this.colors[0][idx]; div.onclick = e => canvas.setColor(this.colors[0][idx]); }); row2.forEach((div idx) => { div.style.backgroundColor = this.colors[1][idx]; div.onclick = e => canvas.setColor(this.colors[1][idx]); }); } }

我们正在接近添加套接字和后端功能以使应用程序具有协作性。 不过,接下来,我们将添加几个按钮来清除绘图并将其下载为图像文件。 我们将在下一篇文章中介绍。

猜您喜欢: