/*
* 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