html5 canvas绘图-多边形的绘制 - zxmeigood
View Post
现在,我们已经将CANVAS绘图环境对象所支持的全部基本图形都讲完了。它们包括:线段、矩形、圆弧、圆形以及贝塞尔曲线。但是,我们肯定需要在canvas之中绘制除此之外的其他图形,比方说,三角形、六边形和八边形。在本节中,你将会学到如下图所示的应用程序,对任意对变形进行描边及填充。
使用moveTo()与lineTo()方法,再结合一些简单的三角函数,就可以绘制出任意边数的多边形。
html代码:
1 <html> 2 <head> 3 <title>Drawing Polygons</title> 4 5 <style> 6 body { 7 background: #eeeeee; 8 } 9 10 #controls { 11 position: absolute; 12 left: 25px; 13 top: 25px; 14 } 15 16 #canvas { 17 background: #ffffff; 18 cursor: pointer; 19 margin-left: 10px; 20 margin-top: 10px; 21 -webkit-box-shadow: 4px 4px 8px rgba(0,0,0,0.5); 22 -moz-box-shadow: 4px 4px 8px rgba(0,0,0,0.5); 23 box-shadow: 4px 4px 8px rgba(0,0,0,0.5); 24 } 25 </style> 26 </head> 27 28 <body> 29 <canvas id=\'canvas\' width=\'850\' height=\'600\'> 30 Canvas not supported 31 </canvas> 32 33 <div id=\'controls\'> 34 Stroke color: <select id=\'strokeStyleSelect\'> 35 <option value=\'red\'>red</option> 36 <option value=\'green\'>green</option> 37 <option value=\'blue\'>blue</option> 38 <option value=\'orange\'>orange</option> 39 <option value=\'cornflowerblue\' selected>cornflowerblue</option> 40 <option value=\'goldenrod\'>goldenrod</option> 41 <option value=\'navy\'>navy</option> 42 <option value=\'purple\'>purple</option> 43 </select> 44 45 Fill color: <select id=\'fillStyleSelect\'> 46 <option value=\'rgba(255,0,0,0.5)\'>semi-transparent red</option> 47 <option value=\'green\'>green</option> 48 <option value=\'rgba(0,0,255,0.5)\'>semi-transparent blue</option> 49 <option value=\'orange\'>orange</option> 50 <option value=\'rgba(100,140,230,0.5)\'>semi-transparent cornflowerblue</option> 51 <option value=\'goldenrod\' selected>goldenrod</option> 52 <option value=\'navy\'>navy</option> 53 <option value=\'purple\'>purple</option> 54 </select> 55 56 Sides: <select id=\'sidesSelect\'> 57 <option value=4 select>4</option> 58 <option value=6>6</option> 59 <option value=8>8</option> 60 <option value=10>10</option> 61 <option value=12>12</option> 62 <option value=20>20</option> 63 </select> 64 65 Start angle: <select id=\'startAngleSelect\'> 66 <option value=0 select>0</option> 67 <option value=22.5>22.5</option> 68 <option value=45>45</option> 69 <option value=67.5>67.5</option> 70 <option value=90>90</option> 71 </select> 72 73 Fill <input id=\'fillCheckbox\' type=\'checkbox\' checked/> 74 <input id=\'eraseAllButton\' type=\'button\' value=\'Erase all\'/> 75 </div> 76 77 <script src = \'example.js\'></script> 78 </body> 79 </html>
example.js代码:
1 var canvas = document.getElementById(\'canvas\'), 2 context = canvas.getContext(\'2d\'), 3 eraseAllButton = document.getElementById(\'eraseAllButton\'), 4 strokeStyleSelect = document.getElementById(\'strokeStyleSelect\'), 5 startAngleSelect = document.getElementById(\'startAngleSelect\'), 6 7 fillStyleSelect = document.getElementById(\'fillStyleSelect\'), 8 fillCheckbox = document.getElementById(\'fillCheckbox\'), 9 10 sidesSelect = document.getElementById(\'sidesSelect\'), 11 12 drawingSurfaceImageData, 13 14 mousedown = {}, 15 rubberbandRect = {}, 16 dragging = false, 17 18 sides = 8, 19 startAngle = 0, 20 21 guidewires = true, 22 23 Point = function (x, y) { 24 this.x = x; 25 this.y = y; 26 }; 27 28 29 // Functions..................................................... 30 31 function drawGrid(color, stepx, stepy) { 32 context.save() 33 34 context.strokeStyle = color; 35 context.fillStyle = \'#ffffff\'; 36 context.lineWidth = 0.5; 37 context.fillRect(0, 0, context.canvas.width, context.canvas.height); 38 39 for (var i = stepx + 0.5; i < context.canvas.width; i += stepx) { 40 context.beginPath(); 41 context.moveTo(i, 0); 42 context.lineTo(i, context.canvas.height); 43 context.stroke(); 44 } 45 46 for (var i = stepy + 0.5; i < context.canvas.height; i += stepy) { 47 context.beginPath(); 48 context.moveTo(0, i); 49 context.lineTo(context.canvas.width, i); 50 context.stroke(); 51 } 52 53 context.restore(); 54 } 55 56 function windowToCanvas(e) { 57 var x = e.x || e.clientX, 58 y = e.y || e.clientY, 59 bbox = canvas.getBoundingClientRect(); 60 61 return { x: x - bbox.left * (canvas.width / bbox.width), 62 y: y - bbox.top * (canvas.height / bbox.height) 63 }; 64 } 65 66 // Save and restore drawing surface.............................. 67 68 function saveDrawingSurface() { 69 drawingSurfaceImageData = context.getImageData(0, 0, 70 canvas.width, 71 canvas.height); 72 } 73 74 function restoreDrawingSurface() { 75 context.putImageData(drawingSurfaceImageData, 0, 0); 76 } 77 78 // Rubberbands................................................... 79 80 function updateRubberbandRectangle(loc) { 81 rubberbandRect.width = Math.abs(loc.x - mousedown.x); 82 rubberbandRect.height = Math.abs(loc.y - mousedown.y); 83 84 if (loc.x > mousedown.x) rubberbandRect.left = mousedown.x; 85 else rubberbandRect.left = loc.x; 86 87 if (loc.y > mousedown.y) rubberbandRect.top = mousedown.y; 88 else rubberbandRect.top = loc.y; 89 } 90 91 function getPolygonPoints(centerX, centerY, radius, sides, startAngle) { 92 var points = [], 93 angle = startAngle || 0; 94 95 for (var i=0; i < sides; ++i) { 96 points.push(new Point(centerX + radius * Math.sin(angle), 97 centerY - radius * Math.cos(angle))); 98 angle += 2*Math.PI/sides; 99 } 100 101 return points; 102 } 103 104 function createPolygonPath(centerX, centerY, radius, sides, startAngle) { 105 var points = getPolygonPoints(centerX, centerY, radius, sides, startAngle); 106 107 context.beginPath(); 108 109 context.moveTo(points[0].x, points[0].y); 110 111 for (var i=1; i < sides; ++i) { 112 context.lineTo(points[i].x, points[i].y); 113 } 114 115 context.closePath(); 116 } 117 118 function drawRubberbandShape(loc, sides, startAngle) { 119 createPolygonPath(mousedown.x, mousedown.y, 120 rubberbandRect.width, 121 parseInt(sidesSelect.value), 122 (Math.PI / 180) * parseInt(startAngleSelect.value)); 123 context.stroke(); 124 125 if (fillCheckbox.checked) { 126 context.fill(); 127 } 128 } 129 130 function updateRubberband(loc, sides, startAngle) { 131 updateRubberbandRectangle(loc); 132 drawRubberbandShape(loc, sides, startAngle); 133 } 134 135 // Guidewires.................................................... 136 137 function drawHorizontalLine (y) { 138 context.beginPath(); 139 context.moveTo(0,y+0.5); 140 context.lineTo(context.canvas.width,y+0.5); 141 context.stroke(); 142 } 143 144 function drawVerticalLine (x) { 145 context.beginPath(); 146 context.moveTo(x+0.5,0); 147 context.lineTo(x+0.5,context.canvas.height); 148 context.stroke(); 149 } 150 151 function drawGuidewires(x, y) { 152 context.save(); 153 context.strokeStyle = \'rgba(0,0,230,0.4)\'; 154 context.lineWidth = 0.5; 155 drawVerticalLine(x); 156 drawHorizontalLine(y); 157 context.restore(); 158 } 159 160 // Event handlers................................................ 161 162 canvas.onmousedown = function (e) { 163 var loc = windowToCanvas(e); 164 165 saveDrawingSurface(); 166 167 e.preventDefault(); // prevent cursor change 168 169 saveDrawingSurface(); 170 mousedown.x = loc.x; 171 mousedown.y = loc.y; 172 dragging = true; 173 }; 174 175 canvas.onmousemove = function (e) { 176 var loc; 177 178 if (dragging) { 179 e.preventDefault(); // prevent selections 180 181 loc = windowToCanvas(e); 182 restoreDrawingSurface(); 183 updateRubberband(loc, sides, startAngle); 184 185 if (guidewires) { 186 drawGuidewires(mousedown.x, mousedown.y); 187 } 188 } 189 }; 190 191 canvas.onmouseup = function (e) { 192 var loc = windowToCanvas(e); 193 dragging = false; 194 restoreDrawingSurface(); 195 updateRubberband(loc); 196 }; 197 198 eraseAllButton.onclick = function (e) { 199 context.clearRect(0, 0, canvas.width, canvas.height); 200 drawGrid(\'lightgray\', 10, 10); 201 saveDrawingSurface(); 202 }; 203 204 strokeStyleSelect.onchange = function (e) { 205 context.strokeStyle = strokeStyleSelect.value; 206 }; 207 208 fillStyleSelect.onchange = function (e) { 209 context.fillStyle = fillStyleSelect.value; 210 }; 211 212 // Initialization................................................ 213 214 context.strokeStyle = strokeStyleSelect.value; 215 context.fillStyle = fillStyleSelect.value; 216 drawGrid(\'lightgray\', 10, 10);
上述程序清单中的代码首先获取了指向canvas绘图环境对象的引用,并且定义了一个名为point的对象。
getPolygonPoints()函数创建并返回了一个含有多边形顶点的数组,这个多边形是由该函数的5个参数所确定的。该函数运用图所写的算式来计算各个顶点的坐标,并创建了一个包含这些顶点的数组。
createPolygonPath()函数调用getPolygonPoints()函数,以获取包含指定多边形各个顶点的数组。该函数先移动到第一个顶点,然后创建一条包含此多边形所有顶点的路径。
最后,应用程序调用drawRubberbandShape()函数来完成多边形的绘制,这个函数是由上次中的那个drawRubberbandShape()函数改编而来的。