<commit_before>/**
 * PrintEngine handles splitting of pedigree into pages for printing and generating print previews
 *
 * @class PrintEngine
 */
var PrintEngine = Class.create({

    initialize: function() {
        // TODO: load default paper settings from pedigree preferences in admin section
        this.printPageWidth  = 1055;
        this.printPageHeight = 756;
        this.printPageWidthPortrait  = 756;
        this.printPageHeightPortrait = 980;
        this.xOverlap = 18;
        this.yOverlap = 18;
    },

    /**
     * @param {emulateFullPage} When true, makes svg include extra blank space up to the pageWidth/pageHeight size
     */
    _generatePages: function(scale, moveHorizontallySize, addOverlaps, pageWidth, pageHeight, includeLegend, emulateFullPage) {
        var totalLegendHeight = 0;
        var legendHTML = "";
        if (includeLegend) {
            // Manually compose legend for print; 3 benefits:
            //   - color samples not using background gcolor (which is not printed by default in some browsers)
            //   - known height (need th eheight to compute required number of pages; no need to pre-render in the browser)
            //   - better handling of disabled/enabled legend items (regular legend has both enabled and disabled items)

            var legendData = editor.getView().getSettings();

            var generateSection = function(colors, names, sectionName) {
                var count  = 0;
                var height = 30;
                var html   = "<div class='legend-section'><h3 class='section-title'>" + sectionName + "</h3>"+
                             "<ul class='abnormality-list'>";
                for (var id in colors) {
                    if (colors.hasOwnProperty(id)) {
                        count++;
                        var color = colors[id];
                        var name  = (names && names.hasOwnProperty(id)) ? names[id] : id;
                        html += "<li class='abnormality'>";
                        html += "<span class='abnormality-color'><svg height='13' width='13' style='display: inline-block;'><rect x='0' y='0' rx='6' ry='6' width='13' height='13' fill='" + color + "'></rect></svg></span>";
                        html += "<span class='legend-item-name'>" + name + "</span>";
                        height += 20;
                    }
                }
                html += "</ul></div>";
                if (count > 0) {
                    return {"html": html, "heightInPixels": height};
                } else {
                    return {"html": "", "heightInPixels": 0};
                }
            }
            var sections = [];
            if (legendData.hasOwnProperty("colors")) {
                legendData["colors"].hasOwnProperty("disorders")  && sections.push(generateSection(legendData["colors"]["disorders"], legendData["names"]["disorders"], "Disorders"));
                legendData["colors"].hasOwnProperty("genes")      && sections.push(generateSection(legendData["colors"]["genes"], null, "Genes"));
                legendData["colors"].hasOwnProperty("phenotypes") && sections.push(generateSection(legendData["colors"]["phenotypes"], null, "Phenotypes"));
                legendData["colors"].hasOwnProperty("cancers")    && sections.push(generateSection(legendData["colors"]["cancers"], null, "Cancers"));
            }

            for (var i = 0; i < sections.length; i++) {
                totalLegendHeight += sections[i].heightInPixels;
                legendHTML        += sections[i].html;
            }
        } // if includeLegend

        var svg = editor.getWorkspace().getSVGCopy();

        //console.log("BBOX: " + stringifyObject(svg.getBBox()));

        svg.scale(scale);

        svg.move(moveHorizontallySize, 0);

        var svgText = svg.getSVGText();
        var bbox    = svg.getBBox();

        var xOverlap = addOverlaps ? Math.floor(this.xOverlap * scale) : 0;
        var yOverlap = addOverlaps ? Math.floor(this.yOverlap * scale) : 0;

        var pagesWide = (bbox.width  < pageWidth)  ? 1 : Math.ceil(bbox.width  / pageWidth);
        var pagesTall = (bbox.height < pageHeight) ? 1 : Math.ceil(bbox.height / pageHeight);
        if (pagesWide > 1 && addOverlaps) {
            var realWidthWithOverlaps = bbox.width + (pagesWide-1)*xOverlap;
            pagesWide = Math.ceil(realWidthWithOverlaps / pageWidth);
        }
        if (pagesTall > 1 && addOverlaps) {
            var realHeightWithOverlaps = bbox.height + (pagesTall-1)*yOverlap;
            pagesTall = Math.ceil(realHeightWithOverlaps / pageHeight);
        }

        // split into pages
        var pages = [];
        var pageStartY = 0;
        var legendOnSeparatePage = false;
        for (var pageNumY = 0; pageNumY < pagesTall; pageNumY++) {
            var rowHeight = emulateFullPage ? pageHeight : Math.min(pageHeight, bbox.height - pageStartY);
            var pagesRow = [];
            var pageStartX = 0;
            for (var pageNumX = 0; pageNumX < pagesWide; pageNumX++) {
                var columnWidth = emulateFullPage ? pageWidth : Math.min(pageWidth,  bbox.width - pageStartX);
                var startX = pageStartX;
                if (emulateFullPage && pagesWide == 1) {
                    startX = pageStartX - (pageWidth - bbox.width)/2;
                }
                var pageSvg = svg.getCopy().setViewBox(startX, pageStartY, columnWidth, rowHeight).getSVGText();
                var page = { "pageName" : "page " + pageNumX + ":" + pageNumY,
                             "svg": pageSvg, "width": columnWidth };
                pagesRow.push(page);
                pageStartX += (columnWidth - xOverlap);
            }
            pages.push(pagesRow);
            if (pageNumY == (pagesTall-1) && pageHeight < rowHeight + totalLegendHeight) {
                legendOnSeparatePage = true;
            }
            pageStartY += (rowHeight - yOverlap);
        }

        return { "pages": pages,
                 "pagesWide": pageNumX,
                 "pagesTall": pageNumY,
                 "needLegendOnSeparatePage": legendOnSeparatePage,
                 "legendHTML": legendHTML,
                 "legendHeight": totalLegendHeight }
    },

    generatePreviewHTML: function(landscape, maxPreviewWidth, maxPreviewHeight, printScale, moveHorizontallySize, addOverlaps) {
        var previewWidth = maxPreviewWidth - 30;<commit_msg>PT-1994: Print pedigree Fixed a bug when rightmost page may be clipped if pedigree was moved right<commit_after>/**
 * PrintEngine handles splitting of pedigree into pages for printing and generating print previews
 *
 * @class PrintEngine
 */
var PrintEngine = Class.create({

    initialize: function() {
        // TODO: load default paper settings from pedigree preferences in admin section
        this.printPageWidth  = 1055;
        this.printPageHeight = 756;
        this.printPageWidthPortrait  = 756;
        this.printPageHeightPortrait = 980;
        this.xOverlap = 18;
        this.yOverlap = 18;
    },

    /**
     * @param {emulateFullPage} When true, makes svg include extra blank space up to the pageWidth/pageHeight size
     */
    _generatePages: function(scale, moveHorizontallySize, addOverlaps, pageWidth, pageHeight, includeLegend, emulateFullPage) {
        var totalLegendHeight = 0;
        var legendHTML = "";
        if (includeLegend) {
            // Manually compose legend for print; 3 benefits:
            //   - color samples not using background gcolor (which is not printed by default in some browsers)
            //   - known height (need th eheight to compute required number of pages; no need to pre-render in the browser)
            //   - better handling of disabled/enabled legend items (regular legend has both enabled and disabled items)

            var legendData = editor.getView().getSettings();

            var generateSection = function(colors, names, sectionName) {
                var count  = 0;
                var height = 30;
                var html   = "<div class='legend-section'><h3 class='section-title'>" + sectionName + "</h3>"+
                             "<ul class='abnormality-list'>";
                for (var id in colors) {
                    if (colors.hasOwnProperty(id)) {
                        count++;
                        var color = colors[id];
                        var name  = (names && names.hasOwnProperty(id)) ? names[id] : id;
                        html += "<li class='abnormality'>";
                        html += "<span class='abnormality-color'><svg height='13' width='13' style='display: inline-block;'><rect x='0' y='0' rx='6' ry='6' width='13' height='13' fill='" + color + "'></rect></svg></span>";
                        html += "<span class='legend-item-name'>" + name + "</span>";
                        height += 20;
                    }
                }
                html += "</ul></div>";
                if (count > 0) {
                    return {"html": html, "heightInPixels": height};
                } else {
                    return {"html": "", "heightInPixels": 0};
                }
            }
            var sections = [];
            if (legendData.hasOwnProperty("colors")) {
                legendData["colors"].hasOwnProperty("disorders")  && sections.push(generateSection(legendData["colors"]["disorders"], legendData["names"]["disorders"], "Disorders"));
                legendData["colors"].hasOwnProperty("genes")      && sections.push(generateSection(legendData["colors"]["genes"], null, "Genes"));
                legendData["colors"].hasOwnProperty("phenotypes") && sections.push(generateSection(legendData["colors"]["phenotypes"], null, "Phenotypes"));
                legendData["colors"].hasOwnProperty("cancers")    && sections.push(generateSection(legendData["colors"]["cancers"], null, "Cancers"));
            }

            for (var i = 0; i < sections.length; i++) {
                totalLegendHeight += sections[i].heightInPixels;
                legendHTML        += sections[i].html;
            }
        } // if includeLegend

        var svg = editor.getWorkspace().getSVGCopy();

        //console.log("BBOX: " + stringifyObject(svg.getBBox()));

        svg.scale(scale);

        svg.move(moveHorizontallySize, 0);

        var svgText = svg.getSVGText();
        var bbox    = svg.getBBox();

        var xOverlap = addOverlaps ? Math.floor(this.xOverlap * scale) : 0;
        var yOverlap = addOverlaps ? Math.floor(this.yOverlap * scale) : 0;

        var pagesWide = (bbox.width  < pageWidth)  ? 1 : Math.ceil(bbox.width  / pageWidth);
        var pagesTall = (bbox.height < pageHeight) ? 1 : Math.ceil(bbox.height / pageHeight);
        if (pagesWide > 1 && addOverlaps) {
            var realWidthWithOverlaps = bbox.width + (pagesWide-1)*xOverlap;
            pagesWide = Math.ceil(realWidthWithOverlaps / pageWidth);
        }
        if (pagesTall > 1 && addOverlaps) {
            var realHeightWithOverlaps = bbox.height + (pagesTall-1)*yOverlap;
            pagesTall = Math.ceil(realHeightWithOverlaps / pageHeight);
        }

        // split into pages
        var pages = [];
        var pageStartY = 0;
        var legendOnSeparatePage = false;
        for (var pageNumY = 0; pageNumY < pagesTall; pageNumY++) {
            var rowHeight = emulateFullPage ? pageHeight : Math.min(pageHeight, bbox.height - pageStartY);
            var pagesRow = [];
            var pageStartX = 0;
            for (var pageNumX = 0; pageNumX < pagesWide; pageNumX++) {
                var columnWidth = (emulateFullPage || (pagesWide > 1 && pageNumX == pagesWide-1))? pageWidth : Math.min(pageWidth,  bbox.width - pageStartX);
                var startX = pageStartX;
                if (emulateFullPage && pagesWide == 1) {
                    startX = pageStartX - (pageWidth - bbox.width)/2;
                }
                var pageSvg = svg.getCopy().setViewBox(startX, pageStartY, columnWidth, rowHeight).getSVGText();
                var page = { "pageName" : "page " + pageNumX + ":" + pageNumY,
                             "svg": pageSvg, "width": columnWidth };
                pagesRow.push(page);
                pageStartX += (columnWidth - xOverlap);
            }
            pages.push(pagesRow);
            if (pageNumY == (pagesTall-1) && pageHeight < rowHeight + totalLegendHeight) {
                legendOnSeparatePage = true;
            }
            pageStartY += (rowHeight - yOverlap);
        }

        return { "pages": pages,
                 "pagesWide": pageNumX,
                 "pagesTall": pageNumY,
                 "needLegendOnSeparatePage": legendOnSeparatePage,
                 "legendHTML": legendHTML,
                 "legendHeight": totalLegendHeight }
    },

    generatePreviewHTML: function(landscape, maxPreviewWidth, maxPreviewHeight, printScale, moveHorizontallySize, addOverlaps) {
        var previewWidth = maxPreviewWidth - 30;
{'fraction_non_alphanumeric': 0.12205633369247344, 'fraction_numerical': 0.009542865938125289, 'mean_word_length': 2.0081018518518516, 'pattern_counts': {'":': 26, '<': 45, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1893433', 'n_tokens_mistral': 3720, 'n_tokens_neox': 3508, 'n_words': 849}