开源 html5 + svg 标注工具 (点标,框标,曲线标) 目前暂时写到图形的绘制与变形,后续完善

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <style>
        .drawActive{
            color: red;
        }
    </style>
    <body>
        <ul >
            <li>
                <button class='rectBtn drawActive'>框标</button>
            </li>
            <li>
                <button class='pointBtn'>点标</button>
            </li>
            <li>
                <button class='lineBtn'>曲线标</button>
            </li>
            <li>
                <button class='regionBtn'>区域标</button>
            </li>
        </ul>
        <svg xmlns="http://www.w3.org/2000/svg" version="1.0" style="background:grey;height: 600px;width:100%">
            <path d="M 366 161 C 366 161 515 266 515 266" stroke="black"/>
        </svg>
        <script>
            var operateType = 'draw' //当前svg操作类型  draw 为 画图   edit 为编辑中
            var editRect = null;//确定不动的点
            var drawType = 'rect'; //标注类型默认框标
            var drawColor = 'red'
            var drawBtnDoms = document.getElementsByTagName('ul')[0].getElementsByTagName('button')
            var drawElement = null; //当前移动的对象
            var pathAssistLineElement = null;//0为定义断电
            var pathAssistRectElement = null;
            var assistElementArray = [];
            for (var i = 0 ; i < drawBtnDoms.length ; i ++ ){
                drawBtnDoms[i].onclick = function(){
                    if(!this.classList.contains('drawActive')){
                        var sblingsDoms = document.getElementsByTagName('ul')[0].querySelectorAll('button')
                        for (var j = 0 ; j < sblingsDoms.length ; j++){
                            sblingsDoms[j].classList.remove('drawActive');
                        }
                        this.classList.add('drawActive');
                        switch(this.innerHTML)
                            {
                                case '框标':
                                  drawType = 'rect';
                                  break;
                                case '点标':
                                  drawType = 'point';
                                  break;
                                case '曲线标':
                                  drawType = 'line';
                                  break;
                                default:
                                  drawType = 'regionBtn';
                            }
                    }
                }
            }
            var svgDom = document.querySelector('svg');
            var isclick= true;
            //svg画布上 鼠标按下事件
            svgDom.onmousedown = function(e){
                if(!isclick){//防止点击过快
                    return false;
                }else{
                    clickQuick();
                }
                if(e.button==0  && (operateType=='draw'||operateType=='edit')){//当前为画图操作
                    switch(drawType)
                       {
                             case 'rect':
                              //判断是否进入编辑边缘 
                                  if(e.target.tagName=='rect' && e.target.dataset.dataType == 'assistRect'){
                                       var rectId = e.target.getAttribute('name');
                                   drawElement = document.getElementById(rectId);
                                   var startX = parseFloat(drawElement.getAttribute('x'));
                                      var startY = parseFloat(drawElement.getAttribute('y'));
                                      var startWidth = parseFloat(drawElement.getAttribute('width'));
                                      var startHeight = parseFloat(drawElement.getAttribute('height'));
                                      var assistX = parseFloat(e.target.getAttribute('x')) + 2;
                                      var assistY = parseFloat(e.target.getAttribute('y')) + 2;
                                      if(assistX==startX && assistY == startY){
                                           editRect=[startX+startWidth,startY+startHeight];
                                      }else if(assistX!=startX && assistY == startY){
                                           editRect=[startX,startY+startHeight];
                                      }else if(assistX!=startX && assistY != startY){
                                           editRect=[startX,startY];
                                      }else{
                                           editRect=[startX+startWidth,startY];
                                      }
                                  operateType = 'edit';
                                  drawElementStyle(2,e.target);
                                  }else{
                                       operateType = 'draw';
                                  }
                                 if(operateType=='draw'){
                                     var currentX = e.offsetX;
                                     var currentY = e.offsetY;
                                     drawElement = document.createElementNS('http://www.w3.org/2000/svg','rect');
                                     drawElement.setAttribute('x',currentX);
                                     drawElement.setAttribute('y',currentY);
                                     drawElement.setAttribute('width',0);
                                     drawElement.setAttribute('height',0);
                                     drawElement.dataset.dataType = 'markRect';
                                     svgDom.appendChild(drawElement);
                                     drawElementStyle(2,drawElement);
                                 }
                                 break;
                           case 'point':
                               //判断是否进入编辑边缘 
                               if(e.target.tagName=='circle'){
                                   drawElement = e.target;  
                                   operateType = 'edit';
                               }else{
                                      operateType = 'draw'; 
                               }
                               if(operateType=='draw'){
                                    var currentX = e.offsetX;
                                        var currentY = e.offsetY;
                                        drawElement = document.createElementNS('http://www.w3.org/2000/svg','circle');    
                                        drawElement.setAttribute('cx',currentX);
                                        drawElement.setAttribute('cy',currentY);
                                        drawElement.setAttribute('r',2);
                                        svgDom.appendChild(drawElement);
                                        drawCircleStyle(0,drawElement);
                               }
                               break;  
                           case 'line':
                               if(operateType=='draw'){
                                    if(drawElement==null){//曲线区域绘画起点
                                           //定义当前操作的曲线区域对象
                                           drawElement = document.createElementNS('http://www.w3.org/2000/svg','path');
                                           //定义起点
                                           var currentStartPath = [e.offsetX,e.offsetY]
                                           drawElement.setAttribute('d','M '+currentStartPath.join(' ')+' C '+currentStartPath.join(' ')+' '+currentStartPath.join(' ')+' '+currentStartPath.join(' '));
                                           var rectId = getUuid();
                                        drawElement.setAttribute('id',rectId);
                                        drawElement.style.fill = 'none';
                                        drawElement.style.stroke = 'black';
                                        drawElement.style.strokeWidth = 2;
                                        svgDom.appendChild(drawElement)
                                    }else{
                                        debugger;
                                        if(e.target.tagName=='rect' && e.target.dataset.dataType == 'pathAssistRect' 
                                        && drawElement.getAttribute('id') == e.target.getAttribute('name')){
                                            debugger;
                                            var currentD = drawElement.getAttribute('d').split(' ');
                                            currentD = currentD.splice(0,currentD.length-7)
                                            currentD.push('z')
                                            drawElement.setAttribute('d',currentD.join(' '));
                                            //清空
                                            drawElement = null;
                                            pathAssistLineElement = null;
                                            pathAssistRectElement = null;
                                            return false;
                                        }
                                        var pathDarray = drawElement.getAttribute('d').split(' ');
                                        var lastItemY = pathDarray[pathDarray.length-1];
                                        var lastItemX = pathDarray[pathDarray.length-2];
                                        var lastItem = [lastItemX,lastItemY];
                                        pathDarray.push('C',lastItem.join(' '),lastItem.join(' '),lastItem.join(' '));
                                        drawElement.setAttribute('d',pathDarray.join(' '))
                                    }
                                    var currentPathId = drawElement.getAttribute('id');
                                       //定义端点线
                                       pathAssistLineElement = document.createElementNS('http://www.w3.org/2000/svg','line');
                                       pathAssistLineElement.setAttribute('x1',e.offsetX);
                                       pathAssistLineElement.setAttribute('y1',e.offsetY);
                                       pathAssistLineElement.setAttribute('x2',e.offsetX);
                                       pathAssistLineElement.setAttribute('y2',e.offsetY);
                                       pathAssistLineElement.setAttribute('name',currentPathId);
                                       pathAssistLineElement.dataset.dataType = 'pathAssistLine'
                                       pathAssistLineElement.style.stroke = 'red';
                                       pathAssistLineElement.style.strokeWidth = 1;
                                       svgDom.appendChild(pathAssistLineElement);
                                       //定义端点
                                       pathAssistRectElement = document.createElementNS('http://www.w3.org/2000/svg','rect');
                                       pathAssistRectElement.setAttribute('x',e.offsetX-1);
                                       pathAssistRectElement.setAttribute('y',e.offsetY-1);
                                       pathAssistRectElement.setAttribute('width',4);
                                       pathAssistRectElement.setAttribute('height',4);
                                       pathAssistRectElement.dataset.dataType = 'pathAssistRect';
                                       pathAssistRectElement.dataset.dataDrawBegin = true;
                                       pathAssistRectElement.setAttribute('name',currentPathId);
                                       svgDom.appendChild(pathAssistRectElement);
                               }
                       }
                   }
            }
            
            //svg画布上 鼠标移动事件
            svgDom.onmousemove = function(e){
                if(drawElement==null){
                    return false;
                }
                if(e.button==0  && (operateType=='draw'||operateType=='edit')){//当前为画图操作
                    switch(drawType)
                       {
                             case 'rect':
                                 if(operateType=='draw'){
                                      var currentX = e.offsetX;
                                      var currentY = e.offsetY;
                                      var startX = drawElement.getAttribute('x');
                                      var startY = drawElement.getAttribute('y');
                                      var rectX = (currentX > startX)? startX:currentX;
                                      var rectY = (currentY > startY)? startY:currentY;
                                      var rectWith = Math.abs(currentX - startX);
                                      var rectHeight = Math.abs(currentY - startY);
                                      drawElement.setAttribute('x',rectX);
                                      drawElement.setAttribute('y',rectY);
                                      drawElement.setAttribute('width',rectWith);
                                      drawElement.setAttribute('height',rectHeight);
                                 }else if(operateType=='edit'){
                                  var currentX = e.offsetX;
                                      var currentY = e.offsetY;
                                      //计算不动点坐标
                                      var startX = editRect[0];
                                      var startY = editRect[1];
                                      var rectX = (currentX > startX)? startX:currentX;
                                      var rectY = (currentY > startY)? startY:currentY;
                                      var rectWith = Math.abs(currentX - startX);
                                      var rectHeight = Math.abs(currentY - startY);
                                      drawElement.setAttribute('x',rectX);
                                      drawElement.setAttribute('y',rectY);
                                      drawElement.setAttribute('width',rectWith);
                                      drawElement.setAttribute('height',rectHeight);
                                 }
                                 break;
                              case 'point':
                                  if(operateType=='draw'){
                                         //目前什么都不做
                                  }else if(operateType=='edit'){
                                          var currentX = e.offsetX;
                                        var currentY = e.offsetY;
                                        pathAssistRectElement.getAttribute('x')+1
                                        pathAssistRectElement.setAttribute('cy',currentY);
                                  }
                                  break;
                              case 'line':
                                  if(operateType=='draw'){
                                      if(pathAssistLineElement){//确定端点
                                              var lineCenterX = parseFloat(pathAssistRectElement.getAttribute('x'))+1;
                                              var lineCenterY = parseFloat(pathAssistRectElement.getAttribute('y'))+1;
                                              var x2 = 2*lineCenterX - e.offsetX;
                                              var y2 = 2*lineCenterY - e.offsetY;
                                              pathAssistLineElement.setAttribute('x1',e.offsetX);
                                              pathAssistLineElement.setAttribute('y1',e.offsetY);
                                              pathAssistLineElement.setAttribute('x2',x2);
                                              pathAssistLineElement.setAttribute('y2',y2);
                                              var pathDarray = drawElement.getAttribute('d').split(' ');
                                              pathDarray.splice(pathDarray.length-6,2,e.offsetX,e.offsetY);
                                              if(pathDarray.length-11>=0){
                                                  pathDarray.splice(pathDarray.length-11,2,x2,y2);
                                              }
                                              drawElement.setAttribute('d',pathDarray.join(' '));
                                      }else{//画曲线
                                              var pathDarray = drawElement.getAttribute('d').split(' ');
                                        pathDarray.splice(pathDarray.length-4,4,e.offsetX,e.offsetY,e.offsetX,e.offsetY);
                                        drawElement.setAttribute('d',pathDarray.join(' '));
                                      }
                                  }    
                       }
                }
            }
            
            //svg画布上  鼠标up事件
            svgDom.onmouseup = function(e){
                if(drawElement==null){
                    return;
                }
                if(e.button==0 && (operateType=='draw' || operateType=='edit')){//当前为画图操作 
                    switch(drawType)
                       {
                             case 'rect':
                                 if(operateType=='draw'){
                                        if(drawElement.getAttribute('width')==0 || drawElement.getAttribute('height')==0){//不符合条件的矩形取消
                                             drawElement.parentNode.removeChild(drawElement);
                                             drawElement = null;
                                             break;
                                        }
                                        drawElementStyle(0,e.target);
                                        drawElement.onmouseenter = function(e){
                                      //没有进入边缘
                                      if(drawType=='rect'){
                                          drawElementStyle(2,e.target);
                                      } 
                                   }
                                   drawElement.onmouseleave = function(e){
                                      //离开边缘
                                      if(drawType=='rect'){
                                          drawElementStyle(0,e.target);
                                      }
                                   }
                                   //辅助编辑元素创建
                                   var rectId = getUuid();
                                   drawElement.setAttribute('id',rectId);
                                   creatAssistRects(drawElement);
                                 }else if(operateType=='edit'){
                                        //删除对应的辅助元素rect
                                        var rectId = drawElement.getAttribute('id');
                                        var assistRects = document.getElementsByName(rectId);
                                        for (var i = assistRects.length-1 ; i >= 0 ; i--){
                                               assistRects[i].onmouseenter = null;
                                               assistRects[i].onmouseleave = null;
                                               assistRects[i].parentNode.removeChild(assistRects[i]);
                                        }
                                        //添加辅助rect
                                        creatAssistRects(drawElement);
                                 }
                                 break;
                              case 'point' :
                                  if(operateType=='draw'){
                                      drawElement.onmouseenter = function(e){
                                       //没有进入边缘
                                       if(drawType=='point'){
                                           drawCircleStyle(1,e.target);
                                       } 
                                   }
                                   drawElement.onmouseleave = function(e){
                                       //离开边缘
                                       if(drawType=='point'){
                                           drawCircleStyle(0,e.target);
                                       }
                                   }
                                  }
                                  break;
                           case 'line':
                               if(operateType=='draw'){
                                   pathAssistLineElement=null;
                                   pathAssistRectElement=null;
                               }
                       }      
                }        
                if(drawType!='line'){
                    drawElement=null
                }
            }
            
            //计算两点距离
            function distanceTwoPoint(x1,y1,x2,y2){
                var x_len = Math.abs(x1-x2);
                var y_len = Math.abs(y1-y2);
                return Math.sqrt(Math.pow(x_len,2) + Math.pow(y_len,2))
            }
            //设置标注对象样式  0:正常状态  1: 高亮状态   2: 可编辑状态
            function drawElementStyle(type,drawElement){
                if(type==0){
                    drawElement.style.fill = 'none';
                    drawElement.style.strokeOpacity = 1;
                     drawElement.style.stroke = drawColor;
                     drawElement.style.strokeDasharray = 'none';
                     drawElement.style.strokeWidth = 1;
                }else if(type==1){
                    drawElement.style.fill = 'none';
                    drawElement.style.strokeOpacity = 0.1;
                     drawElement.style.stroke = drawColor;
                     drawElement.style.strokeDasharray = 'none';
                     drawElement.style.strokeWidth = 1;
                }else if(type==2){
                    drawElement.style.fill = 'none';
                    drawElement.style.strokeOpacity = 1;
                     drawElement.style.stroke = drawColor;
                     drawElement.style.strokeDasharray = '4,2';
                     drawElement.style.strokeWidth = 1;
                }
                
            }
            
            //辅助矩形标注对象样式
            function drawElementAssistStyle(type, assistElement){
                if(type==0){
                    assistElement.style.fill = drawColor;
                     assistElement.style.strokeWidth = 0;
                     assistElement.style.fillOpacity = 0;
                }else if(type==1){
                    assistElement.style.fill = drawColor;
                    assistElement.style.fillOpacity = 1;
                     assistElement.style.strokeWidth = 0;
                }
            }
            
            //圆样式添加
            function drawCircleStyle(type,drawElement){
                if(type==0){
                    drawElement.style.fill = drawColor;
                    drawElement.style.stroke = drawColor;
                    drawElement.style.fillOpacity = 1;
                    drawElement.style.strokeOpacity = 1;
                    drawElement.style.strokeWidth = 1;
                }else if(type==1){
                    drawElement.style.fill = drawColor;
                    drawElement.style.stroke = drawColor;
                    drawElement.style.fillOpacity = 0.5;
                    drawElement.style.strokeOpacity = 0.5;
                    drawElement.style.strokeWidth = 1;
                }
            }
            
            //添加辅助画图矩形元素
            function creatAssistRects(drawElement){
                var rectX = parseFloat(drawElement.getAttribute('x'));
                var rectY = parseFloat(drawElement.getAttribute('y'));
                var rectWith = parseFloat(drawElement.getAttribute('width'));
                var rectHeight = parseFloat(drawElement.getAttribute('height'));    
                var rectAssistArray = [[rectX-2,rectY-2],[rectX+rectWith-2,rectY-2],[rectX+rectWith-2,rectY+rectHeight-2],[rectX-2,rectY+rectHeight-2]];
                for (var citem = 0 ; citem < 4 ; citem++){
                    var rectAssist = document.createElementNS('http://www.w3.org/2000/svg','rect');
                    rectAssist.setAttribute('x',rectAssistArray[citem][0]);
                    rectAssist.setAttribute('y',rectAssistArray[citem][1]);
                    rectAssist.setAttribute('width',4);
                    rectAssist.setAttribute('height',4);
                    rectAssist.setAttribute('name',drawElement.getAttribute('id'));
                    rectAssist.dataset.dataType = 'assistRect';
                    svgDom.appendChild(rectAssist);
                    drawElementAssistStyle(0,rectAssist);
                    //绑定鼠标移入移出事件
                    rectAssist.onmouseenter = function(e){
                        //进入边缘
                        if(drawType=='rect'){
                            drawElementAssistStyle(1,e.target);
                        } 
                    }
                    rectAssist.onmouseleave = function(e){
                        //离开边缘
                        if(drawType=='rect'){
                            drawElementAssistStyle(0,e.target);
                        }
                    }
                }
            }
            
            //生成唯一的uuid
            function getUuid(){
                var mydate = new Date();
                return  "mbh"+mydate.getDay()+ mydate.getHours()+ mydate.getMinutes()+mydate.getSeconds()+mydate.getMilliseconds();
            }
            
            function clickQuick(){
                if(isclick){
                    isclick= false;
                    setTimeout(function(){ 
                        isclick = true;
                    }, 500);
                }
            }
        </script>
    </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值