D3 JS SVG конвертировать в PNG и скачать - PullRequest
0 голосов
/ 09 марта 2020

Я новичок в d3 js и могу загрузить SVG как png, но я столкнулся с некоторыми проблемами, пожалуйста, помогите мне.

Проблемы:

  1. Когда диаграмма расширена до ее большого размера, она не может быть загружена. Переменная blob равна null.
canvas.toBlob(function (blob) {
    var filesize = Math.round(blob.length / 1024) + ' KB';
    if (callback) callback(blob, filesize);
});
Когда я загружаю изображение, оно содержит дополнительное пустое пространство. Изображение действительно загружается, когда диаграмма мала.

Вот мой код скрипта: -

// svg

function draw(redraw) {
    var dragGroup = d3.behavior.drag()
        .on('dragstart', function () {
            d3.event.sourceEvent.stopPropagation();
        }).on('drag', function (d, i) {
        });

    // var w = document.getElementById("chart").clientWidth;
    // var h = document.getElementById("chart").clientHeight;
    // if (download === true) {
    // s.wSVG = '';//document.getElementById("productHierarchychart").clientWidth + 333;
    // s.hSVG = '';//document.getElementById("productHierarchychart").clientHeight + (-45);
    //}
    //else
    //{
    s.wSVG = document.getElementById("productHierarchychart").clientWidth + 333;
    s.hSVG = document.getElementById("productHierarchychart").clientHeight + (-45);
    //}

    // s.wSVG = window.innerWidth
    // s.hSVG = window.innerHeight

    s.depth = 1;

    s.margin = { top: 20, right: 120, bottom: 60, left: 80 };
    s.wChart = s.wSVG - s.margin.left - s.margin.right;
    s.hChart = s.hSVG - s.margin.top - s.margin.bottom;

    d3.select("#svgtag").remove();
    s.nodesize = s.mode === "h" ? [s.def_x_nodesize - s.nodesizechg, s.def_y_nodesize - s.nodesizechg] : [s.def_x_nodesize + 230, s.def_y_nodesize];
    s.tree = d3.layout.tree().nodeSize(s.nodesize);
    s.diagonal = d3.svg.diagonal()
        .projection(function (d) {
            // return s.mode === "h" ? [d.y, d.x] : [d.x, d.y];
            return s.mode === "h" ? [d.y + rectH + 20, d.x + rectW + (-02)] : [d.x + rectW + (-10), d.y + rectH + 40];
        });
    s.vis = d3.select(s.parent)
        .append("svg:svg")
        .attr("id", "svgtag")
        // .attr("width", window.innerWidth)
        // .attr("height", window.innerHeight)
        .attr("width", s.wSVG)
        .attr("height", s.hSVG)
        // .call(s.zm = d3.behavior.zoom().scaleExtent([1, 3]).on("zoom", redraw)).append("g")
        .append("svg:g")
        .attr("id", "gtagimage")
        .attr("transform", "translate(" + (s.mode === "v" ? ((s.wSVG + 100) / 2.5) : (s.margin.left)) + "," + (s.mode === "v" ? ((s.margin.top) - 60) : ((s.hSVG / 2) - 100)) + ")")
        .append("svg:g")
        .call(dragGroup)
        .attr("id", "changeG")
        .attr("class", "drawarea")
        .append("svg:g")
        .attr("transform", "translate(" + s.margin.left + "," + s.margin.top + ")");
    s.root = s.data;
    s.maxDepth = 6;
    s.root.x0 = s.mode === "h" ? s.hChart / 2 : s.wChart / 2;
    s.root.y0 = s.mode === "h" ? 0 : -100;

    var zooming = d3.select("svg")
        .call(d3.behavior.zoom()
            .scaleExtent([0.5, 5])
            .on("zoom", zoom));
    zooming.on("dblclick.zoom", null);
    zooming.on("mousewheel.zoom", null);
    zooming.on("DOMMouseScroll.zoom", null); // disables older versions of Firefox
    zooming.on("wheel.zoom", null);
    // Initialize the display to show a few nodes.        
    if (redraw === false) {
        s.root.children.forEach(toggleAll);
        //            s.root.children.forEach(collapse_1);
    }
    update(s.root);

}

function collapse_1(d) {
    if (d.children) {
        d._children = d.children;
        d._children.forEach(collapse_1);
        d.children = null;
    }
}

function toggleAll(d) {
    if (d.children) {
        d.children.forEach(toggleAll);
        toggle(d);
    }
}

var div = d3.select("body").append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

function update(source) {
    var duration = d3.event && d3.event.altKey ? 5000 : 500;

    // Compute the new tree layout.
    var nodes = s.tree.nodes(s.root).reverse();
    // Normalize for fixed-depth.
    nodes.forEach(function (d) {
        //            var dx=0;
        //            if(d.x<s.root.x0){
        //                dx=d.x - ((d.name.length*(12)));
        //            }else{
        //                dx=d.x + ((d.name.length*(12)));
        //            }
        d.y = s.mode === "h" ? d.depth * 320 : d.y === 0 ? d.depth * 40 : d.depth * 135;                    // To Change the link height distance
        // d.y = s.mode === "h" ? d.depth * 280 : d.depth * 135;                    // To Change the link height distance
        //            d.x= s.mode === "h" ? d.x : dx;  
    });

    // Update the nodes
    var node = s.vis.selectAll("g.node")
        .data(nodes, function (d) { return d.id || (d.id = ++s.i) })
        .attr("data-expanded", function (d) {
            if (d['children']) {
                return true;
            } else {
                return false;
            }
        });

    // Enter any new nodes at the parent's previous position.
    var nodeEnter = node.enter().append("svg:g")
        .attr("class", function (d) {
            var typeName = (d.nodeType ? d.nodeType : d.empid);
            typeName = typeName.replace(/ /g, '').toLowerCase();
            return typeName + " node";
        })
        .attr("transform", function (d) { return s.mode === "h" ? "translate(" + (source.y0 === 0 ? 0 : (source.y0 + 40)) + "," + (source.x0 + (-15)) + ")" : "translate(" + (source.x0 + (-25)) + "," + (source.y0 === 0 ? 40 : (source.y0 + 05)) + ")" })
        .attr("data-expanded", function (d) {
            if (d['children']) {
                return true;
            } else {
                return false;
            }
        })

        .on("mouseover", texty)
        .on("mouseout", removeTexty)
        .on("click", click);

    var link = s.vis.selectAll("path.link")
        .data(s.tree.links(nodes), function (d) {
            return d.target.id;
        });

    // Enter any new links at the parent's previous position.
    link.enter().insert("svg:path", "g")
        .attr("class", "link")
        //                .attr("id",function(d,i){return d.source.name.replace(/ /g,'')+'-'+d.source.children[i].name.replace(/ /g,'');})  
        .attr("d", function (d) {
            var o = { x: source.x0, y: source.y0 };
            return s.diagonal({ source: o, target: o });
        })
        .transition()
        .duration(duration)
        .attr("d", s.diagonal);
    // Transition links to their new position.
    link.transition()
        .duration(duration)
        .attr("d", s.diagonal)
        .attr("class", function (d) {
            var text = $("#txtPosition").data('kendoComboBox').value();
            if (text !== "") {
                if (d.target.class !== undefined && d.target.class.includes("found")) {
                    return "link link-found";
                }
                else {
                    return "link";
                }
            }
            else {
                return "link";
            }
        });

    // Transition exiting nodes to the parent's new position.
    link.exit().transition()
        .duration(duration)
        .attr("d", function (d) {
            var o = { x: source.x, y: source.y };
            return s.diagonal({ source: o, target: o });
        })
        .remove();

    nodeEnter.append("svg:rect")
        .attr("x", "-100px")
        .attr("y", "-15px")
        .attr("id", function (d) {
            return (d.empid + "rectest");
        })
        .attr("width", "230px")
        .attr("height", "55px")
        .attr("border-radius", "25px !important")
        .style("fill", "rgb(255,255,255)")
        .style("stroke-width", "1")
        //.style("stroke", "rgb(53,150,216)")
        .style("stroke", "rgb(204, 204, 204)")
        .style("rx", "3")

    nodeEnter.append("image")
        .attr("id", function (d) {
            return d.empid;
        })
        .attr("xlink:href", function (d) {
            var data = "";
            $.ajax({
                type: 'POST',
                url: PhotoUrl,
                async: false,
                cache: false,
                data: { Image1: d.Image, EmpID: d.empid },
                success: function (response) {
                    data = response;
                }
            });
            return data;
        })
        .attr("x", "-95px")
        .attr("y", "-7px")
        .attr("width", "40px")
        .attr("height", "40px");

    nodeEnter.append("svg:foreignObject")
        .attr("width", 170)
        .attr("height", 25)
        .attr("x", -50)
        .attr("y", -5)
        .attr("class", "foreignObject1")
        .append("xhtml:body")
        .style("font", "14px 'Helvetica Neue'")
        .attr("width", 170)
        .attr("height", 18)
        .attr("dx", ".35em")
        .attr("dy", ".35em")
        .attr("text-anchor", "unset")
        .style("background-color", "white")
        .style("fill-opacity", 1e-6)
        .html(function (d) {
            return ("<span class='texthide Nametext'>" + d.name + " (" + d.empid + ")" + "</span>");
        });

    nodeEnter.append("svg:foreignObject")
        .attr("width", 125)
        .attr("height", 25)
        .attr("x", -50)
        .attr("y", 15)
        .append("xhtml:body")
        .style("font", "14px 'Helvetica Neue'")
        .attr("width", 170)
        .attr("height", 18)
        .attr("dx", ".35em")
        .attr("dy", ".35em")
        .attr("text-anchor", "unset")
        .style("background-color", "white")
        .style("fill-opacity", 1e-6)
        .html(function (d) {
            return ("<span class='texthide designationtext'>" + d.designation + "</span>");
        });

    nodeEnter.append("svg:foreignObject")
        .attr("width", 45)
        .attr("height", 25)
        .attr("x", 80)
        .attr("y", 15)
        .append("xhtml:body")
        .style("font", "14px 'Helvetica Neue'")
        .attr("width", 170)
        .attr("height", 18)
        .attr("dx", ".35em")
        .attr("dy", ".35em")
        .attr("text-anchor", "unset")
        .style("background-color", "white")
        .style("fill-opacity", 1e-6)
        .html(function (d) {
            if (d.noofchild > 0) {
                return ("<span class='pull-right noofchildtext'><img src='Assets/Images/Orgchart_Reportees.png' style='width: 14px; margin-top: -2px; fill : #91a4a5;'/>" + d.noofchild + "</span>");
            }
        });

//Photo

    $('#saveButton').click(function (e) {
        var oldx = $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[0];
        var oldy = $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[1].slice(0, $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[1].length - 1);
        $("#svgtag").attr("width", " ");
        $("#svgtag").attr("height", " ");
        var svgString = getSVGString(d3.select('svg').node());

        if ($("#gtagimage")[0].getBoundingClientRect().width > 1200) {
            svgString2Image(svgString, ((($("#gtagimage")[0].getBoundingClientRect().width + 2000))), ($("#gtagimage")[0].getBoundingClientRect().height + 500), 'png', save); // passes Blob and filesize String to the callback
        }
        else {
            svgString2Image(svgString, ($("#gtagimage")[0].getBoundingClientRect().width + 2000), ($("#gtagimage")[0].getBoundingClientRect().height + 500), 'png', save); // passes Blob and filesize String to the callback
        }

        $("#svgtag").attr("width", "1256");
        $("#svgtag").attr("height", "485");
        d3.select('g').transition()
            .duration(400)
            //.attr('transform', 'translate(' + 542.4 + ',' + -40 + ')');
            .attr('transform', 'translate(' + oldx + ',' + oldy + ')');
    });

    function save(dataBlob, filesize) {
        saveAs(dataBlob, 'ESSOrgChart.png'); // FileSaver.js function
    }

    function getSVGString(svgNode) {
        var cssStyleText = getCSSStyles(svgNode);
        appendCSS(cssStyleText, svgNode);

        var serializer = new XMLSerializer();
        var svgString = serializer.serializeToString(svgNode);
        if ($("#gtagimage")[0].getBoundingClientRect().width > 1200) {
            var oldx = $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[0];
            svgString = svgString.replace(oldx, $("#gtagimage")[0].getBoundingClientRect().width);
            var oldy = $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[1].slice(0, $("#gtagimage")[0].getAttribute("transform").substr(10).split(",")[1].length - 1)
            svgString = svgString.replace(oldy, (parseInt(oldy) + (600)));
        }
        svgString = svgString.replace("path.link { fill: none; stroke: rgb(204, 204, 204); stroke-width: 1.5px; }", "path.link { fill: none; stroke: rgb(204, 204, 204); stroke-width: 5px; }");

        return svgString;
    }

    function getCSSStyles(parentElement) {
        var selectorTextArr = [];

        // Add Parent element Id and Classes to the list
        selectorTextArr.push('#' + parentElement.id);
        for (var c = 0; c < parentElement.classList.length; c++)
            if (!contains('.' + parentElement.classList[c], selectorTextArr))
                selectorTextArr.push('.' + parentElement.classList[c]);

        // Add Children element Ids and Classes to the list
        var nodes = parentElement.getElementsByTagName("*");
        for (var i = 0; i < nodes.length; i++) {
            var id = nodes[i].id;
            if (!contains('#' + id, selectorTextArr))
                selectorTextArr.push('#' + id);

            var classes = nodes[i].classList;
            for (var c = 0; c < classes.length; c++)
                if (!contains('.' + classes[c], selectorTextArr))
                    selectorTextArr.push('.' + classes[c]);
        }

        // Extract CSS Rules
        var extractedCSSText = "";
        for (var i = 0; i < document.styleSheets.length; i++) {
            var s = document.styleSheets[i];

            try {
                if (!s.cssRules) continue;
            } catch (e) {
                if (e.name !== 'SecurityError') throw e; // for Firefox
                continue;
            }

            var cssRules = s.cssRules;
            for (var r = 0; r < cssRules.length; r++) {
                if (includes(cssRules[r].selectorText, selectorTextArr))
                    extractedCSSText += cssRules[r].cssText;
            }
        }

        return extractedCSSText;

        function contains(str, arr) {
            return arr.indexOf(str) === -1 ? false : true;
        }

        function includes(str, arr) {
            if ("undefined" !== typeof str) {
                for (var q = 0; q < arr.length; q++) {
                    if (str.indexOf(arr[q]) !== -1) { return true; }
                }
            }
        }
    }

    function appendCSS(cssText, element) {
        var styleElement = document.createElement("style");
        styleElement.setAttribute("type", "text/css");
        styleElement.innerHTML = cssText;
        var refNode = element.hasChildNodes() ? element.children[0] : null;
        element.insertBefore(styleElement, refNode);
    }

    function svgString2Image(svgString, width, height, format, callback) {
        var format = format ? format : 'png';

        var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString))); // Convert SVG string to data URL

        var canvas = document.createElement("canvas");
        var context = canvas.getContext("2d");

        canvas.width = width;
        canvas.height = height;

        var image = new Image();
        image.onload = function () {
            context.clearRect(0, 0, width, height);
            context.drawImage(image, 0, 0, width, height);

            canvas.toBlob(function (blob) {
                var filesize = Math.round(blob.length / 1024) + ' KB';
                if (callback) callback(blob, filesize);
            });


        };

        image.src = imgsrc;
    }
...