多页打印

DawninShadow 2020-01-02 PM 1093℃ 0条

在微光时画框框,在一只时画框框,到了ProcessOn继续画框框...只能说冥冥中自有天意吧

话说这天我们老大找到我,指着竞品公司的打印功能,发出个给我也整一个的声音..瞄了一眼也就是个切割打印嘛.这锅我背了...
217791577180499_.pic.jpg
就是这么个东东
着手开发,让我看看JS的打印函数.print()函数,调了就打,没参数没配置,简单粗暴且笨拙.为了应付这简单粗暴的打印,也只能用这种暴力的代码:

        printPart: function (idstr) { //idstr 要打印内容中的id
            var el = document.getElementById(idstr);
            var iframe = document.createElement('IFRAME');
            var doc = null;
            iframe.setAttribute('style', 'position:absolute;width:0px;height:0px;left:0px;top:0px;');
            document.body.appendChild(iframe);
            doc = iframe.contentWindow.document;
            var SVGDom = el.innerHTML;
            doc.write('<div style="position:absolute; left:0px;top:1123px;" >' + el.innerHTML + '</div>');
            doc.body.setAttribute('style', 'margin:0px; padding:0px;')
            doc.close();
            iframe.contentWindow.focus();
            iframe.contentWindow.print();
            if (navigator.userAgent.indexOf("MSIE") > 0) { // 对于IE一下移除iframe
                document.body.removeChild(iframe);
            }
            document.body.removeChild(iframe);
        }

所以,想要保证打满整张纸只能在要打印的东西上做文章,A4尺寸,英寸转毫米,系统DPI各种参数算了半天,然后自己又调了调,得到了A4纸的PX数 W:1176,H:1670,固定参数写进去简单粗暴

        paperSize:{
            'A4':{
                W:1135,
                H:1616,
            },
            'A3':{
                W:1684,
                H:2382,
            }
        },

然后就是怎么创建一个所见即所得的待打印DOM了.本来想的是直接在画布上做个切割然后搞成img扔过去就得了,但是拿到代码我傻了,这东西竟然是个SVG,而且为了更好的实现缩放,不可能搞个特别大的canvas吧它包进去,所以视图框(图中的蓝框,最后对应一个A4纸)还是要拿dom来做.思路有了,那无非就是切割 和 再定位.
SVG咱没玩过啊,查查怎么切割,嗯,clip-path.思想跟Canvas不一样(一个遮罩一个裁剪),但效果差不多.Ps:svg的资料好少.
然后是裁剪,矩形相交算法简单粗暴,计算出来的值丢过去裁剪就完事了:

        RectangleOverlap: function (rec1, rec2) { //获取SVG对应裁剪部分
            var Xstart = Math.max(rec1.X, rec2.X); //A矩形的xStart和B矩形的Xstart 大的值
            var Xend = Math.min(rec1.X+rec1.W, rec2.X+rec2.W); //A矩形的xend和B矩形的Xend 小的值
            var Ystart = Math.max(rec1.Y, rec2.Y) //A矩形的YStart和B矩形的Ystart 大的值 
            var Yend = Math.min(rec1.Y+rec1.H, rec2.Y+rec2.H) //A矩形的Yend和B矩形的Yend 小的值 
            return {
                X:Xstart,
                Y:Ystart,
                W:Xend - Xstart,
                H:Yend - Ystart
            }
        },

OK,思路差不多了,剩下的问题就是统一坐标轴了,和做定位了.看图不难看出我们最终要生成 Math.ceil(SVG.W/Box.W) * Math.ceil(SVG.H/Box.H) 个视图框
而起始的偏移量是则是1/2的location.H - printSVG.SVG.H % location.H或者0(其实可以强制都加一,减少为0的情况) .这样才能保证图片都被包含进去了
然后就是视窗的排序啊,删除啊,移动啊这类操作,比较值得说的也就是拖动处理了,注意两点移动监听和抬起监听写在鼠标点击事件中,而且要绑定在整体dom上,这样才不会导致鼠标移动太快出了Box监听范围,初始值设置好防止刚拖动时Box跳动.鼠标抬起后把移动监听取消掉
最后是总代码:

    // 设定一个id为SVGDom的div,然后让svg为其子节点,自动撑起它的宽高 
 var printSVG = {   
        SVG:{
            X: '',
            Y: '',
            W: '',
            H: '',
        },
        draw : SVG('#mind-svg-con'),
        boxType: '', //across or vertical
        paperType: 'A4',
        paperSize:{
            'A4':{
              W:1135,
              H:1616,
            },
            'A3':{
                W:1684,
                H:2382,
            }
        },
        boxData:{}, // 二维数组 box的 XY轴定位由box的相对定位(top,left)加上SVG的offset值求得
        boxHeap:[], 
        drag:{
            diffX:'',
            diffY:'',
            target:''
        },
        init: function () {
          //  var DPI = this.js_getDPI();// 其实用不到
            printSVG.SVG.W  = $('#SVGDom').width(); 
            printSVG.SVG.H  = $('#SVGDom').height(); 
            printSVG.SVG.X = $('#SVGDom').offset().left;
            printSVG.SVG.Y = $('#SVGDom').offset().top;
            !this.boxType && (this.boxType = this.SVG.W > this.SVG.H ? 'across' : 'vertical') //获取纸型
        },
        drawBox: function(location,id){
            function DomBox(){
                // bg-c  rgba(36,153,249,0.1)  --> rgba(36,153,249,0.2);
                //   1px solid #2499f9 
                var div = document.createElement("div");
                div.style.position = 'absolute'
                div.style.width = this.W;
                div.style.height = this.H;
                div.style.top = this.Y;
                div.style.left = this.X;
                div.style.backgroundColor = 'rgba(36,153,249,0.1)';
                div.style.zIndex = '5';
                div.style.border = '1px solid #2499f9 ';
                div.onmousedown = this.onDragStart;
                div.mousemove = this.onDragMove;
                div.mouseup = this.onDragEnd;
                var num = $('<div class="index"></div>');
                num.css({
                    'width': '30px',
                    'height': '30px',
                    'border-radius': '50%',
                    'background-color':'rgb(36,153,249)',
                    'position': 'absolute',
                    'margin': '10px',
                    'color': '#fff',
                    'line-height': '30px',
                    'text-align': 'center',
                    'font-weight': '600',
                    'font-size': '20px',
                })
                div.append(num[0])
                var close = $('<div class="close">X</div>');
                close.css({
                    'width': '30px',
                    'height': '30px',
                    'border-radius': '50%',
                    'background-color':'#f73859',
                    'cursor': 'pointer',
                    'position': 'absolute',
                    'display': 'none',
                    'right': '0px',
                    'margin': '10px',
                    'color': '#fff',
                    'line-height': '30px',
                    'text-align': 'center',
                    'font-weight': '600',
                    'font-size': '20px',
                })
                close.on('click',function(){
                    var id = $(this).parent().attr('id')
                    debugger
                     delete printSVG.boxData[id];
                    $("#"+id).remove();
                    printSVG.sortBox()
                })
                div.append(close[0])
                return div;
            };
            function BoxObj(location){
                // console.log('location:',location)
                this.W = location.W+'px';
                this.H = location.H+'px';
                this.X = location.X+'px';
                this.Y = location.Y+'px';
                this.onDragStart = function(){
                    printSVG.resetBox()
                    $(this).css({
                        'backgroundColor' : 'rgba(36,153,249,0.2)',
                        'z-index' : $(this).css('z-index') + 1
                    });
                    $(this).children('.close').css({
                    'display':'block'
                    })
                    var e = event || window.event;
                    printSVG.drag.target = $(this).attr('id');
                    printSVG.drag.diffY = e.clientY - $(this).css('top').slice(0,-2);
                    printSVG.drag.diffX = e.clientX - $(this).css('left').slice(0,-2);
                    console.log('drag start', e.clientX, 'Box:',$(this).css('left').slice(0,-2))
                    $(document).bind("mousemove",printSVG.onDragMove);
                    $(document).bind("mouseup",printSVG.onDragEnd);
                };

            } 
            var obj = new BoxObj(location);
            var node = DomBox.call(obj)
            node.id = id;
            $('#bigBox').append(node);
        },
        onDragMove : function(){
                    var e = event || window.event;
                    // console.log('drag move',e.clientX,'Box:', e.clientX - printSVG.drag.diffX )
                    if(printSVG.drag.target){
                        $('#'+printSVG.drag.target).css({
                            'left': (e.clientX - printSVG.drag.diffX ) + "px",
                            'top': (e.clientY - printSVG.drag.diffY ) + "px",
                        })
                        printSVG.boxData[printSVG.drag.target].X = printSVG.SVG.X + (e.clientX - printSVG.drag.diffX );
                        printSVG.boxData[printSVG.drag.target].Y = printSVG.SVG.Y + (e.clientY - printSVG.drag.diffY );
                        console.log(printSVG.boxData[printSVG.drag.target])
                    }
                },
        onDragEnd : function(){
                    printSVG.drag.target = '';
                    $(document).unbind("mousemove mouseup");
                },
        resetBox: function(){
            for(var id in printSVG.boxData){
                $("#"+id).css({'backgroundColor' : 'rgba(36,153,249,0.1)','z-index': '5'})
                $("#"+id).children('.close').css({
                    'display':'none'
                })
            }
        },
        clearBox: function(){
            for(var id in printSVG.boxData){
                delete printSVG.boxData[id];
                $("#"+id).remove()
            }
        },
        sortBox: function(){
            var num = 1;
            for(var id in printSVG.boxData){
                $("#"+id).children('.index').text(num)
                num++
            }
        },
        boxLayout: function(){ //裁剪框初始布局
            var location = printSVG.boxType == 'vertical' ? { 'W': printSVG.paperSize[printSVG.paperType].W , 'H': printSVG.paperSize[printSVG.paperType].H } : { 'W': printSVG.paperSize[printSVG.paperType].H , 'H': printSVG.paperSize[printSVG.paperType].W };
            var boxNumForX = Math.ceil(printSVG.SVG.W / location.W)
            var boxExcursionX = printSVG.SVG.W % location.W ? (location.W -  printSVG.SVG.W % location.W  ) / 2 : 0;
            var boxNumForY = Math.ceil(printSVG.SVG.H / location.H)
            var boxExcursionY = printSVG.SVG.H % location.H ?  (location.H -  printSVG.SVG.H % location.H  ) / 2 : 0;
            for(var i = 0; i<boxNumForX; i++){
                location.X = i * location.W - boxExcursionX;
                for(var j = 0; j<boxNumForY;j++){
                    location.Y = j * location.H - boxExcursionY;
                    printSVG.boxData['box'+i+j] = {
                        W: location.W,
                        H: location.H,
                        X: location.X + printSVG.SVG.X, // location其实是相对于SVG的偏移量而不是绝对的top left定位
                        Y: location.Y + printSVG.SVG.Y,
                    };
                    printSVG.drawBox(location,'box'+i+j);
                }
            }
            printSVG.sortBox()
        },
        js_getDPI: function() {  //获取DPI
                var arrDPI = new Array();
                if (window.screen.deviceXDPI != undefined) {
                    arrDPI[0] = window.screen.deviceXDPI;
                    arrDPI[1] = window.screen.deviceYDPI;
                } else {
                    var tmpNode = document.createElement("DIV");
                    tmpNode.style.cssText =
                        "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden";
                    document.body.appendChild(tmpNode);
                    arrDPI[0] = parseInt(tmpNode.offsetWidth);
                    arrDPI[1] = parseInt(tmpNode.offsetHeight);
                    tmpNode.parentNode.removeChild(tmpNode);
                }
                return arrDPI;
            },
        printSVG: function () { //打印SVG
            var iframe = document.createElement('IFRAME');
            var doc = null;
            iframe.setAttribute('style', 'position:absolute;width:0px;height:0px;left:0px;top:0px;');
            document.body.appendChild(iframe);
            for(var id in printSVG.boxData){
               var  Rectangle = printSVG.RectangleOverlap(printSVG.boxData[id],printSVG.SVG); //获取相交部分
               printSVG.SVGclip(Rectangle); //裁剪SVG
               printSVG.renderRes(printSVG.boxData[id],printSVG.SVG,'rgba(36,153,249,0.1)'); // 生成待打印纸张
            } 
            iframe.contentWindow.focus();
            iframe.contentWindow.print();
            if (navigator.userAgent.indexOf("MSIE") > 0) { // 对于IE一下移除iframe
                document.body.removeChild(iframe);
            }
            document.body.removeChild(iframe);
        },
        SVGclip:function(REClocation){
            var ellipse = printSVG.draw.rect(REClocation.W, REClocation.H).move(REClocation.X - printSVG.SVG.X , REClocation.Y - printSVG.SVG.Y);
            var clip =  printSVG.draw.clip().add(ellipse);
            printSVG.draw.clipWith(clip);
        },
        rmoveSVGclip:function(REClocation){
            var ellipse = printSVG.draw.rect(printSVG.SVG.W, printSVG.SVG.H).move(0,0);
            var clip =  printSVG.draw.clip().add(ellipse);
            printSVG.draw.clipWith(clip);
        },
        RectangleOverlap: function (rec1, rec2) { //获取SVG对应裁剪部分
            var Xstart = Math.max(rec1.X, rec2.X); //A矩形的xStart和B矩形的Xstart 大的值
            var Xend = Math.min(rec1.X+rec1.W, rec2.X+rec2.W); //A矩形的xend和B矩形的Xend 小的值
            var Ystart = Math.max(rec1.Y, rec2.Y) //A矩形的YStart和B矩形的Ystart 大的值 
            var Yend = Math.min(rec1.Y+rec1.H, rec2.Y+rec2.H) //A矩形的Yend和B矩形的Yend 小的值 
            return {
                X:Xstart,
                Y:Ystart,
                W:Xend - Xstart,
                H:Yend - Ystart
            }
        },
        renderRes:function(Box,SVG,bg){ // Box是渲染出来的蓝色框.   SVG为原来的SVG
            var div = $("<div></div>");
                div.css({
                    'position': 'relative',
                    'width': Box.W+10,
                    'height': Box.H+10,
                    'backgroundColor': bg,
                    'overflow':'hidden',
                    'padding': '25px',
                    // 'outline' : '1px red solid'
                    // 'transform-origin': '0 0 0',
                    // 'transform': 'scale(2)'
                })
           var  SVGDom = $('#SVGDom').clone();
           SVGDom.css({
            'position': 'relative',
            'left' : SVG.X - Box.X,
            'top': SVG.Y  - Box.Y
           })
            div.append(SVGDom);
            $("iframe")[0].contentWindow.document.body.append(div[0]);
            // $('.res').append(div);
        }
    }
    
  标签: none

非特殊说明,本博所有文章均为博主原创。

评论啦~