直接上代碼,復制粘貼就能用:
HTML代碼:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script src="Public/jquery.min.js" type="text/javascript"></script> <style type="text/css"> canvas { background:#ccc; display:block; margin:0 auto; } #controls { width:200px; height:100%; position:absolute; left:0; top:0; background:linear-gradient(to bottom,#000000,#b8b8b8); user-select:none; } #controls section { margin-top:10px; height:20px; } #controls .label { width:50%; height:20px; line-height:20px; text-align:center; color:#FFF; display:block; float:left; } #xing { float:right; width:50%; height:20px; } /*#shape { */ /*width:50%; height:20px; display:block; */ /* } */ #controls .color { width:50%; height:auto; float:right; } #colors input { float:right; width:48%; height:20px; border:none; } #widths input { float:right; width:49%; height:20px; border:none; } #style { float:right; width:49%; height:20px; border:none; } input[type=button] { width:150px; height:30px; background:#C40000; color:#FFF; border-radius:5px; margin-top:10px; margin-left:10px; border:none; display:block; } </style> </head> <body> <canvas width="500" height="500"></canvas> <div id="controls"> <section id="shape"> <label for="shape" class="label">選擇形狀 : </label> <select id="xing"> <option value="rect">矩形</option> <option value="line">直線</option> <option value="circle">內切圓</option> <option value="circle1">外接圓</option> <option value="circle2">中心圓</option> <option value="poly">多邊形</option> <option value="pen">鉛筆</option> <option value="eraser">橡皮</option> <option value="arrow">箭頭</option> </select> </section> <section id="colors"> <label for="color" class="label">選擇顏色 : </label> <input type="color" id="color"> </section> <section id="widths"> <label for="color" class="label">選擇線寬 : </label> <input type="number" id="width" value="2" step="2" min="2" max="20"> </section> <section id="styles"> <label for="shape" class="label">選擇方式 : </label> <select id="style"> <option value="stroke">描邊</option> <option value="fill">填充</option> </select> </section> <section id="sides"> <label for="side" class="label">選擇邊數 : </label> <input type="number" id="side" value="3" min="3" max="20"> </section> <input type="button" value="撤銷" id="redo"> <input type="button" value="保存" id="save"> <input type="button" value="清空" id="qingkong"> </div> </body> </html>
JS代碼:
var canvas = document.querySelector("canvas"); var cobj = canvas.getContext("2d"); var shape = document.querySelector("#xing"); var color = document.querySelector("#color"); var width = document.querySelector("#width"); var style = document.querySelector("#style"); var side = document.querySelector("#side"); var redo = document.querySelector("#redo"); var save = document.querySelector("#save"); var qingkong = document.querySelector("#qingkong"); console.log(side); var data = []; var s = "rect"; shape.onchange = function() { s = this.value; }; var c = "#000"; color.onchange = function() { c = this.value; }; var w = "2"; width.onchange = function() { w = this.value; }; var st = "stroke"; style.onchange = function() { st = this.value; }; var sd = "3"; side.onchange = function() { sd = this.value; }; canvas.onmousedown = function(e) { var ox = e.offsetX; var oy = e.offsetY; var draw = new Draw(cobj, { color: c, width: w, style: st, side: sd }); if (s == "pen") { cobj.beginPath(); cobj.moveTo(ox, oy); } canvas.onmousemove = function(e) { var mx = e.offsetX; var my = e.offsetY; if (s != "eraser") { cobj.clearRect(0, 0, 500, 500); if (data.length != 0) { cobj.putImageData(data[data.length - 1], 0, 0, 0, 0, 500, 500); //將某個圖像數據放置到畫布指定的位置上 后面四個參數可省略 } } // cobj.strokeRect(ox,oy,mx-ox,my-oy); // cobj.beginPath() draw[s](ox, oy, mx, my, sd); }; document.onmouseup = function() { data.push(cobj.getImageData(0, 0, 500, 500)); //獲取畫布當中指定區域當中所有的圖形數據 canvas.onmousemove = null; document.onmouseup = null; } }; redo.onclick = function() { if (data.length == 0) { alert("無效操作"); return; } cobj.clearRect(0, 0, 500, 500); data.pop(); if (data.length == 0) { return; } cobj.putImageData(data[data.length - 1], 0, 0, 0, 0, 500, 500); }; save.onclick = function() { var r = canvas.toDataURL(); location.assign(r) }; qingkong.onclick = function() { cobj.clearRect(0, 0, 500, 500); data = []; } class Draw { constructor(cobj, option) { this.cobj = cobj; this.color = option.color; this.width = option.width; this.style = option.style; } init() { //初始化 this.cobj.strokeStyle = this.color; this.cobj.fillStyle = this.color; this.cobj.lineWidth = this.width; } rect(ox, oy, mx, my) { this.init(); this.cobj.beginPath(); this.cobj.rect(ox, oy, mx - ox, my - oy); this.cobj[this.style](); } line(ox, oy, mx, my) { this.init(); this.cobj.beginPath(); this.cobj.moveTo(ox, oy); this.cobj.lineTo(mx, my); this.cobj.stroke(); } circle(ox, oy, mx, my) { //內切圓 this.init(); this.cobj.beginPath(); /* var r=Math.sqrt(Math.pow(mx-ox,2)+Math.pow(my-oy,2))/2; this.cobj.arc(ox+(mx-ox)/2,oy+(my-oy)/2,r,0,2*Math.PI);*/ var r = Math.abs(mx - ox) > Math.abs(my - oy) ? Math.abs(my - oy) / 2 : Math.abs(mx - ox) / 2; this.cobj.arc(ox + (ox < mx ? r : -r), oy + (oy < my ? r : -r), r, 0, 2 * Math.PI); this.cobj[this.style](); } circle1(ox, oy, mx, my) { //外接圓 this.init(); this.cobj.beginPath(); var r = Math.sqrt(Math.pow(mx - ox, 2) + Math.pow(my - oy, 2)) / 2; this.cobj.arc(ox + (mx - ox) / 2, oy + (my - oy) / 2, r, 0, 2 * Math.PI); this.cobj[this.style](); } circle2(ox, oy, mx, my) { //中心圓 this.init(); this.cobj.beginPath(); var r = Math.sqrt(Math.pow(mx - ox, 2) + Math.pow(my - oy, 2)); this.cobj.arc(ox, oy, r, 0, 2 * Math.PI); this.cobj[this.style](); } poly(ox, oy, mx, my, sd) { this.init(); this.cobj.save(); cobj.translate(ox, oy); this.cobj.rotate(Math.PI / 2); var angle = Math.PI / sd; var r = Math.sqrt(Math.pow(mx - ox, 2) + Math.pow(my - oy, 2)); var x = Math.cos(angle) * r; var y = Math.sin(angle) * r; this.cobj.beginPath(); this.cobj.moveTo(x, y); for (var i = 0; i < sd; i++) { this.cobj.lineTo(x, -y); this.cobj.rotate(-angle * 2) } this.cobj[this.style](); this.cobj.restore() } pen(ox, oy, mx, my) { this.init(); this.cobj.lineTo(mx, my); this.cobj.stroke(); } eraser(ox, oy, mx, my) { this.cobj.clearRect(mx, my, 10, 10); } arrow(ox, oy, mx, my){//箭頭工具 this.init(); beginPoint.x = ox; beginPoint.y = oy; stopPoint.x = mx; stopPoint.y = my; Plot.arrowCoord(beginPoint, stopPoint); Plot.sideCoord(); Plot.drawArrow(); } } var beginPoint = {};//畫箭頭需要的開始坐標 var stopPoint = {};//畫箭頭需要的結束坐標 var polygonVertex = [];//箭頭多邊形頂點的坐標 var CONST = {//箭頭參數 edgeLen: 50, angle: 25 }; //封裝的作圖箭頭工具對象 var Plot = { angle: "", //在CONST中定義的edgeLen以及angle參數 //短距離畫箭頭的時候會出現箭頭頭部過大,修改: dynArrowSize: function() { var x = stopPoint.x - beginPoint.x, y = stopPoint.y - beginPoint.y, length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); if (length < 250) { CONST.edgeLen = CONST.edgeLen/2; CONST.angle = CONST.angle/2; } else if(length<500){ CONST.edgeLen=CONST.edgeLen*length/500; CONST.angle=CONST.angle*length/500; } // console.log(length); }, //getRadian 返回以起點與X軸之間的夾角角度值 getRadian: function(beginPoint, stopPoint) { Plot.angle = Math.atan2(stopPoint.y - beginPoint.y, stopPoint.x - beginPoint.x) / Math.PI * 180; //console.log(Plot.angle); paraDef(50,40); Plot.dynArrowSize(); }, ///獲得箭頭底邊兩個點 arrowCoord: function(beginPoint, stopPoint) { polygonVertex[0] = beginPoint.x; polygonVertex[1] = beginPoint.y; polygonVertex[6] = stopPoint.x; polygonVertex[7] = stopPoint.y; Plot.getRadian(beginPoint, stopPoint); polygonVertex[8] = stopPoint.x - CONST.edgeLen * Math.cos(Math.PI / 180 * (Plot.angle + CONST.angle)); polygonVertex[9] = stopPoint.y - CONST.edgeLen * Math.sin(Math.PI / 180 * (Plot.angle + CONST.angle)); polygonVertex[4] = stopPoint.x - CONST.edgeLen * Math.cos(Math.PI / 180 * (Plot.angle - CONST.angle)); polygonVertex[5] = stopPoint.y - CONST.edgeLen * Math.sin(Math.PI / 180 * (Plot.angle - CONST.angle)); }, //獲取另兩個底邊側面點 sideCoord: function() { var midpoint = {}; // midpoint.x = polygonVertex[6] - (CONST.edgeLen * Math.cos(Plot.angle * Math.PI / 180)); // midpoint.y = polygonVertex[7] - (CONST.edgeLen * Math.sin(Plot.angle * Math.PI / 180)); midpoint.x=(polygonVertex[4]+polygonVertex[8])/2; midpoint.y=(polygonVertex[5]+polygonVertex[9])/2; polygonVertex[2] = (polygonVertex[4] + midpoint.x) / 2; polygonVertex[3] = (polygonVertex[5] + midpoint.y) / 2; polygonVertex[10] = (polygonVertex[8] + midpoint.x) / 2; polygonVertex[11] = (polygonVertex[9] + midpoint.y) / 2; }, //畫箭頭 drawArrow: function() { cobj.beginPath(); cobj.moveTo(polygonVertex[0], polygonVertex[1]); cobj.lineTo(polygonVertex[2], polygonVertex[3]); cobj.lineTo(polygonVertex[4], polygonVertex[5]); cobj.lineTo(polygonVertex[6], polygonVertex[7]); cobj.lineTo(polygonVertex[8], polygonVertex[9]); cobj.lineTo(polygonVertex[10], polygonVertex[11]); // cobj.lineTo(polygonVertex[0], polygonVertex[1]); cobj.closePath(); cobj.fill(); } }; //自定義參數 function paraDef(edgeLen, angle) { CONST.edgeLen = edgeLen; CONST.angle = angle; }
效果圖: