/* * date : 2017-03-29 * purpose: canvas画板功能优化 * author: ii迷糊 */ var fontSize = 14;//字体大小 var _textarea_w = fontSize * 4;//默认文字输入域的宽度 var _textarea_h = fontSize * 2 + 2;//默认文字输入域的高度 var isload=true; var newindex=0; var _text = "";//记录最后输入的数据 var maxWidth = 548; //纯文字答案输出行宽限定 var lineHeight = 20; var lineX = 10; //文字输出时的起始横坐标 function setTareaAutoWH(id,maxW,maxH,e) { var width = 0, height = 0; var obj = document.getElementById(id); var text = obj.value; var top = parseInt(obj.style.top.replace("px", ""), 10); var left = parseInt(obj.style.left.replace("px", ""), 10); var _text_length = text.length; var lastChart = text.substring((_text_length-1),_text_length); var obj_height = $(‘#text‘).height(); if((obj.scrollHeight)<_textarea_h) { height = _textarea_h; }else{ height = obj_height; } if ((lastChart == "\n") || (lastChart == "\r")){// 根据输入的换行符,计算输入框textarea的高度 height = obj_height + fontSize + 2; } obj.style.height = height + "px"; // 宽度 if((_text_length*fontSize)<_textarea_w){ width = _textarea_w; }else{ //当坐标值+Textarea宽度大于最宽值时,Textarea宽度为可视区域最佳宽度 for(var i=0;i<_text_length;i++){ if(maxW && ((left + width + 5) > (maxW-10))){ width -= 5; break; } } width = (i * fontSize); } obj.style.width = width + "px"; obj.value = text; _text = text; } var type = 0;//1=框,2=圈,3=箭头,4=线,5=手写,6=文字 function setType(_type){ $(‘#text‘).mouseout(); type = _type; for(var i=1;i<=10;i++){ if(_type!=i){ $("#pzem"+i).removeClass("pz_baron"); } else{ $("#pzem"+i).attr("class","pz_baron"); } } } var actions = []; //动作集 //获取对象位置 function getpos(o) { //gets position of object o var bo, x, y, b; x = y = 0; if(document.getBoxObjectFor) { //moz bo = document.getBoxObjectFor(o); x = bo.x; y = bo.y; } else if (o.getBoundingClientRect) { //ie (??) bo = o.getBoundingClientRect(); x = bo.left; y = bo.top; } else { //opera, safari etc while(o && o.nodeName != ‘BODY‘) { x += o.offsetLeft; y += o.offsetTop; b = parseInt(document.defaultView.getComputedStyle(o,null).getPropertyValue(‘border-width‘)); if(b > 0) { x += b; y +=b; } o = o.offsetParent; } } return { x:x, y:y } } //画矩形 function drawRectangle(x,y,x2,y2,ctx,temp){ var w = x2- x; var h = y2-y; ctx.beginPath(); ctx.rect(x, y, w, h); ctx.stroke(); } //画椭圆 function drawEllipse(x1, y1, x2, y2, ctx, mod) { //bounding box. this maybe isn‘t the best idea? var dx = Math.abs(x2-x1); var dy = Math.abs(y2-y1); if(mod && !(dx==dy)) { //shift held down: constrain if(dx < dy) { x2 = x1+(((x2-x1)/dx)*dy); } else { y2 = y1+(((y2-y1)/dy)*dx); } } var KAPPA = 4 * ((Math.sqrt(2) -1) / 3); var rx = (x2-x1)/2; var ry = (y2-y1)/2; var cx = x1+rx; var cy = y1+ry; ctx.beginPath(); ctx.moveTo(cx, cy - ry); ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); ctx.stroke(); } //画线 function drawLine(x1,y1,x2,y2,ctx,temp){ ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); } //画箭头线 function drawLineArrow(x1,y1,x2,y2,ctx,temp){ //画线 ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); //画箭头 ctx.save(); ctx.translate(x2,y2);//箭头原点 ctx.lineWidth=2; ctx.beginPath(); (y2-y1 >= 0) ? ctx.rotate(Math.PI-Math.atan((x2-x1)/(y2-y1))) : ctx.rotate(-Math.atan((x2-x1)/(y2-y1))); //旋转弧度 ctx.lineTo(-2,5); ctx.lineTo(0,2); ctx.lineTo(2,5); ctx.lineTo(0,0); ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.restore(); ctx.closePath(); } //输入文字 function drawText(x1,y1,t_width,text,ctx,temp){ ctx.font = fontSize+"px Microsoft Yahei"; text = text.replace(‘*‘,‘*‘); text = text.replace(/\r\n/g,‘*‘); text = text.replace(/\r?\n/g,‘*‘); var colWidth = 0; var x,y; x = x1; y = y1; for(var i=0;i<text.length;i++){ colWidth += ctx.measureText(text[i]).width; if(colWidth > t_width || text[i].indexOf(‘*‘)!=-1){ y += fontSize; x = x1; if(colWidth > t_width){ i -= 1 ; } colWidth = 0; continue; } ctx.fillStyle = ‘#f00‘; ctx.fillText(text[i], x, y); x += ctx.measureText(text[i]).width; ctx.restore(); } } /** * loadImageURL - 加载图片 * * @param {Object} cx 上下文 * @param {String} url 图片地址 * @param {Number} x 坐标x * @param {Number} y 坐标y * @return {Void} */ function loadImageURL(cx, url, x, y) { var image = document.createElement("img"); image.addEventListener("load", function() { var offL= document.getElementById(‘_canvas‘).offsetLeft; var offT = document.getElementById(‘_canvas‘).offsetTop; var canW = document.getElementById(‘_canvas‘).width; var canH = document.getElementById(‘_canvas‘).height; var mouseX = parseFloat(x); var mouseY = parseFloat(y); var offL_canW = offL + canW; var offT_canH = offT + canH; if(mouseX < (offL + 5)){ mouseX = offL + 5; } if( mouseX> (offL_canW - 30)){ mouseX = offL_canW - 30; } if(mouseY < (offT - 5)){ mouseY = offT + 5; } if(mouseY > (offT_canH - 30)){ mouseY = offT_canH - 30; } cx.drawImage(image, mouseX, mouseY, 30, 30); }); image.src = url; } //清除画布 function clearCanvas(id,flag){ var canvas = document.getElementById(id); if(canvas){ var ctx = canvas.getContext("2d"); ctx.clearRect(0, 0, canvas.width, canvas.height); } if(flag){ actions = []; } } //后退动作 function backAction(objele){ var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); clearCanvas("canvas"); resetAnswerImg(objele); var _actions = []; var len = actions.length; for(var i=0;i<len-1;i++){ var action = actions[i]; draw(action.type,action.place,action.extend,ctx,false); _actions.push(action); } actions = _actions; } // _canvas 路径画布重绘 function resetAnswerImg(objele){ var obj = $(objele); var canvas1 = document.getElementById("canvas"); var ctx1 = canvas1.getContext("2d"); var canvas_height = canvas1.height; var draw_img_width = $(‘#pzDiv1‘).data(‘draw_img_width‘); var draw_img_height = $(‘#pzDiv1‘).data(‘draw_img_height‘); if(obj.html().indexOf(‘<img ‘)!=-1 || obj.html().indexOf(‘<IMG ‘)!=-1){ var img = new Image(); img.src = $(‘img‘,obj).attr(‘src‘); var newWh = ResizeImg([img.width,img.height],[canvas1.width,canvas1.height]); if (newWh.length == 2){ ctx1.drawImage(img, 0, 0, draw_img_width, draw_img_height); } else { ctx1.drawImage(img,0,0); } ctx1.beginPath(); }else{ var tempText = $(obj).find(‘.textanswer_o‘).html(); ctx1.font="14px Microsoft Yahei"; ctx1.fillStyle = ‘#000‘; if(tempText.indexOf(‘<p>‘)!=-1 && tempText.indexOf(‘</p>‘)!=-1){ var temp = tempText.replaceAll(‘<p>‘,‘‘).split(‘</p>‘); var line = 1, temp_length = temp.length; if(temp_length > 14){ canvas.height =(temp_length+2)*20 ; } for(var i=0;i<temp_length;i++){ var value = temp[i].replaceAll(‘ ‘,‘ ‘); value=removeHTMLTag(value); var strs = value.split(""); var w = 0,start = 0; for(var j=0;j<strs.length;j++){ // 文字里的每一行 w += ctx1.measureText(strs[j]).width; if(w>(maxWidth-lineHeight)){ ctx1.fillText(value.substring(start,j),lineX,lineHeight*line); w = 0; start = j; line ++; } } ctx1.fillText(value.substring(start),lineX,20*line); line++; } }else{ ctx1.fillText(tempText,lineX,lineHeight); } ctx1.fillStyle= ‘#f00‘; } } //过滤html标签 function removeHTMLTag(str) { str = str.replace(/<\/?[^>]*>/g,‘‘); //去除HTML tag str = str.replace(/[ | ]*\n/g,‘\n‘); //去除行尾空白 // str=str.replace(/ /ig,‘‘);//去掉 return str; } //获取图片 function getImg(id){ var canvas = document.getElementById(id); if(canvas){ (document.getElementById(‘text‘)) ? canvas.parentNode.removeChild(document.getElementById(‘text‘)) : null; var imgId = id+"_showImg"; (document.getElementById(imgId)) ? canvas.parentNode.parentNode.removeChild(document.getElementById(imgId)) : null; var img = canvas.toDataURL("image/png"); var imgObj = document.createElement("img"); imgObj.id = imgId; imgObj.src = img; canvas.parentNode.parentNode.appendChild(imgObj); } } /* 绘画接口 type:绘画类型,1=矩形 2=椭圆 3=箭头 4=直线 5=手写 6=输入 place:坐标,[X开始坐标,Y开始坐标,X结束坐标,Y结束坐标];当类型为手写时是坐标集合 ctx:画板对象 temp: */ function draw(type,place,extend,ctx,temp){ var offL= document.getElementById(‘_canvas‘).offsetLeft; var offT = document.getElementById(‘_canvas‘).offsetTop; var canW = document.getElementById(‘_canvas‘).width; var canH = document.getElementById(‘_canvas‘).height; var offL_canW = offL + canW; var offT_canH = offT + canH; if( place[2] < offL){ //绘画区域限定 place[2] = offL; }else if(place[2] > offL_canW){ place[2] = offL_canW; } if(place[3] < offT){ place[3] = offT }else if(place[3] > offT_canH){ place[3] = offT_canH; } if(type==1){ drawRectangle(place[0],place[1],place[2], place[3],ctx,temp); } else if(type==2){ drawEllipse(place[0],place[1],place[2], place[3],ctx,false); } else if(type==3){ drawLineArrow(place[0],place[1],place[2], place[3],ctx,temp); } else if(type==4){ drawLine(place[0],place[1],place[2], place[3],ctx,temp); } else if(type==5){ if(place.length>0){ ctx.beginPath(); ctx.moveTo(place[0][0],place[0][1]); for(var i = 0;i<place.length;i++){ var p = place[i]; ctx.quadraticCurveTo(p[0],p[1],p[2], p[3]); } ctx.stroke(); } } else if(type==6){ if(extend){ drawText(place[0],place[1],extend.width,extend.text,ctx,temp); } } else if (type === 7) { loadImageURL(ctx,‘/images/correct.png‘, place[0],place[1]) } else if (type === 8) { loadImageURL(ctx,‘/images/error.png‘, place[0],place[1]) } else if (type === 9) { loadImageURL(ctx,‘/images/A_plus.png‘, place[0],place[1]) } else if (type === 10) { loadImageURL(ctx,‘/images/A_min.png‘, place[0],place[1]) } } //创建绘画面板对象 canvasAnnotate = function(canvasId,obj){ var version=navigator.userAgent; if(version.indexOf("MSIE")!=-1){ var trim_Version=version.split(";")[1].replace(/[ ]/g,""); //获取pc系统信息navigator.userAgent.split(";")[1].replace(/[ ]/g,"") trim_Version = trim_Version.replace("MSIE",""); trim_Version = parseInt(trim_Version,10); if(trim_Version<9) { return; } } var $indexobj = ‘#textarea‘+$(obj).data(‘subfix‘); this.btnDiv = ‘‘; this.btnDiv+=‘<div class="pz_bar pz_100 f14">‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(1);"><span id="pzem1"><em class="pz_icon1"></em>画框</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(2);"><span id="pzem2"><em class="pz_icon2"></em>画圆</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(3);"><span id="pzem3"><em class="pz_icon3"></em>箭头</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(4);"><span id="pzem4"><em class="pz_icon4"></em>画线</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(5);"><span id="pzem5" class="pz_baron"><em class="pz_icon5"></em>画笔</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="setType(6);"><span id="pzem6"><em class="pz_icon6"></em>输入</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="backAction(\‘‘+$indexobj+‘\‘);"><span><em class="pz_icon7"></em>撤销</span></a>‘; this.btnDiv +=‘<a href="javascript:void(0);" onClick="clearCanvas(\‘canvas\‘,true);resetAnswerImg(\‘‘+$indexobj+‘\‘);"><span><em class="pz_icon8"></em>清屏</span></a>‘; this.btnDiv += ‘<a href="javascript:void(0);" onClick="setType(7);"><span id="pzem7"><em class="pz_icon9"></em>正确</span></a>‘; this.btnDiv += ‘<a href="javascript:void(0);" onClick="setType(8);"><span id="pzem8"><em class="pz_icon10"></em>错误</span></a>‘; this.btnDiv += ‘<a href="javascript:void(0);" onClick="setType(9);"><span id="pzem9"><em class="pz_icon12"></em>A+</span></a>‘; this.btnDiv += ‘<a href="javascript:void(0);" onClick="setType(10);"><span id="pzem10"><em class="pz_icon13"></em>A-</span></a>‘; this.btnDiv +=‘</div>‘; this.strokeStyle = "red";//画笔颜色 this._strokeStyle = "blue";//临时画笔颜色 var canvas = document.getElementById(canvasId); var ctx = canvas.getContext("2d"); ctx.strokeStyle = this.strokeStyle; if($(‘#annotateDiv‘).html() == undefined){ var annotateDiv = document.createElement(‘div‘); annotateDiv.id ="annotateDiv"; canvas.parentNode.appendChild(annotateDiv); } if($(‘#canvasDiv2‘).html() == undefined){ var canvasDiv = document.createElement(‘div‘); canvasDiv.id = "canvasDiv2"; canvasDiv.style.position = "relative"; canvasDiv.appendChild(canvas); $(‘#annotateDiv‘).append(canvasDiv); } if($(‘#operatingDiv‘).html() == undefined){ var operatingDiv = document.createElement(‘div‘); operatingDiv.id = "operatingDiv"; operatingDiv.innerHTML = this.btnDiv; $(‘#annotateDiv‘).append(operatingDiv); } //创建临时画布,用于动态显示绘画状态 var canvastemp = document.createElement(‘canvas‘); canvastemp.id = "_"+canvasId; canvastemp.width = $( "#pzDiv1").width(); canvastemp.height = $(‘#canvas‘).height(); canvastemp.style.position = "absolute"; canvastemp.style.top = "0px"; canvastemp.style.left = "0px"; canvastemp.setAttribute(‘oncontextmenu‘, ‘return false‘); $(‘#canvasDiv2‘).append(canvastemp); var _ctx = canvastemp.getContext("2d"); _ctx.strokeStyle = this._strokeStyle; var _x,_y; var x_start,y_start,x_end,y_end; var start = false; var pos = getpos(canvastemp); var place = []; $(‘#text‘).live(‘mouseout‘,function(){ $(‘#_canvas‘).mousedown(); }); canvastemp.onmousedown = function(e){ place = []; pos = getpos(canvastemp);//update 20130911 if(document.getElementById(‘text‘)){ if(document.getElementById(‘text‘).value.replace(" ","")!=""){ x_start += 0; y_start += fontSize; var text = document.getElementById(‘text‘).value; var t_width = document.getElementById(‘text‘).scrollWidth; place = [x_start,y_start]; var extend = {"width":t_width,"text":text}; draw(6,place,extend,ctx,false); var action = {"type":type,"place":place,"extend":{"width":t_width,"text":text}}; actions.push(action); } this.parentNode.removeChild(document.getElementById(‘text‘)); } if(e.clientX == undefined){ return false; } x_start = _x = e.clientX-pos.x+1; y_start = _y = e.clientY-pos.y+1; start = true; if(type==6){ if((x_start + _textarea_w) > canvastemp.scrollWidth){ x_start = canvastemp.scrollWidth - _textarea_w - 5; } if((y_start + _textarea_h) > canvastemp.scrollHeight){ y_start = canvastemp.scrollHeight - _textarea_h - 5 ; } //创建textarea var textarea = document.createElement(‘textarea‘); var t_maxWidth = canvastemp.scrollWidth-x_start - 10; var t_maxHeight = canvastemp.scrollHeight-y_start - 10; textarea.id = "text"; textarea.style.position = ‘absolute‘; textarea.style.top = (y_start) + "px"; textarea.style.left = (x_start) + "px"; textarea.style.width = _textarea_w +‘px‘; textarea.style.maxWidth = t_maxWidth + ‘px‘; textarea.style.height = _textarea_h +‘px‘; textarea.style.maxHeight = t_maxHeight + ‘px‘; textarea.style.background = ‘rgba(0, 0, 0, 0)‘; textarea.style.border = ‘1px dashed #f00‘; textarea.style.wordWrap = ‘break-word‘; textarea.style.color = ‘red‘; textarea.style.fontSize = ‘14px‘; textarea.setAttribute(‘oninput‘, ‘setTareaAutoWH("text",‘+canvastemp.scrollWidth+‘,‘+canvastemp.scrollHeight+‘)‘); textarea.setAttribute(‘onpropertychange‘, ‘setTareaAutoWH("text",‘+canvastemp.scrollWidth+‘,‘+canvastemp.scrollHeight+‘)‘); this.parentNode.appendChild(textarea); setTimeout("document.getElementById(‘text‘).focus();",100); } }; canvastemp.onmousemove = function(e){ clearCanvas(canvastemp.id); if(start && type!=0){ pos = getpos(canvastemp);//update 20130911 x_end = _x = e.clientX-pos.x+1; y_end = _y = e.clientY-pos.y+1; if(type==3){ if( ((x_start - x_end)<2 && (x_start - x_end)>-2) || ((y_start - y_end)<2 && (y_start - y_end)>-2) ){ return; } } if(type!=5){ place = [x_start, y_start, x_end, y_end]; } draw(type,place,null,_ctx,false); if(type==5){ var move = [x_start, y_start, x_end, y_end]; place.push(move); x_start = x_end; y_start = y_end; } } }; canvastemp.onmouseup = function(e){ clearCanvas(canvastemp.id); if(start && type!=0){ pos = getpos(canvastemp);//update 20130911 x_end = _x = e.clientX-pos.x+1; y_end = _y = e.clientY-pos.y+1; if(type==3){ if( ((x_start - x_end)<2 && (x_start - x_end)>-2) || ((y_start - y_end)<2 && (y_start - y_end)>-2) ){ return; } } if(type!=6){ (document.getElementById(‘text‘)) ? this.parentNode.removeChild(document.getElementById(‘text‘)) : ""; } if(type!=5){ place = [x_start, y_start, x_end, y_end]; } draw(type,place,null,ctx,false); if(type!=6){ //记录动作 var action = {"type":type,"place":place,"y2":y_end}; actions.push(action); } place = []; } start = false; }; window.onmouseup = canvastemp.onmouseup; window.onmousemove = canvastemp.onmousemove; //获取图片内容 this.getImg = function(){ if(canvas){ return canvas.toDataURL("image/png"); } return null; }; //设置按钮样式 this.setBtnDiv = function(divHtml){ // operatingDiv.innerHTML = divHtml; $(‘#operatingDiv‘).html(divHtml); return null; } };
本文出自 “琉璃岁月” 博客,谢绝转载!
原文地址:http://11mihu.blog.51cto.com/6659352/1915937