canvasAnotote_resize.js

/*
* 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('&nbsp;',' ');
            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(/&nbsp;/ig,'');//去掉&nbsp;
   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;
   }

};

wKioL1jwXfWigVYfAACtN80Uc_0437.png-wh_50

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章