Chrome svg rendering issues - d3 - polylines

大憨熊 提交于 2020-02-05 05:13:25

问题


I am experiencing issues when rendering a d3 svg graph with polylines. It does work on chrome Version 70.0.3538.67 (Official Build) (64-bit) but not on my current version Version 78.0.3904.108 (Official Build) (64-bit). I am using d3 version v5.9.2.

The issue does not occur when I remove the polylines connecting my d3 rendered foreign objects.

The "shadows", moves around depending on how I move the picture around/zooming, sometimes all of them are gone but a few shadows are most often shown.

I read that dashed lines might cause this, but I have the same issue even if the polylines are normal.

The code I have for rendering the SVG graph looks as follows:

// Function to generate entire d3 tree structure
function graphFoundObjects(response) {
    currentFlowchartView = "graphMode";
    var graphWidth = jQuery("#outputWrapperFlowchart").width();
    var graphHeight = jQuery("#outputWrapperFlowchart").height();

    var nodeWidth = 320;
    var nodeHeight = 90;

    var outputContainerFlowchart = createOutputContainerFlowchart("outputContainerFlowchartChart");
    appendElementToDom("outputWrapperFlowchart", outputContainerFlowchart);

    var graphWrapper = jQuery("#outputContainerFlowchartChart").append("<svg id='graphWrapper'></svg>");
    var graphSvg = d3.select("#graphWrapper").attr("width", graphWidth).attr("height", graphHeight);

    var simulation = d3.forceSimulation(response.nodes)
        .force("charge", d3.forceManyBody().strength(-78000))
        .force("center", d3.forceCenter(graphWidth / 2, graphHeight / 2))
        .force("link", d3.forceLink(response.links).id(function(d) {return d.uuid; }).distance(250).strength(1))
        .force("x", d3.forceX(graphWidth / 2).strength(1))
        .force("y", d3.forceY(graphHeight / 2).strength(1))
        .stop();

    // Fix setting instead so you can choose if you want to center root node by calling the function
    response.nodes[0].firstNode = true;
    function centerFirstNode() {
        graph.nodes[0].fixed = true;
        graph.nodes[0].fx = width / 2;
        graph.nodes[0].fy = height / 2;
    }

    d3.timeout(function() {
        for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) {
            simulation.tick();
        }

        var g = graphSvg.append("g")
                .attr("class", "everything");

        var arrow = g.append("defs").append("marker")
            .attr("id", "arrow")
            .attr("viewBox", "0 -5 10 10")
            .attr("refX", 0)
            .attr("refY", 0)
            .attr("markerWidth", 7)
            .attr("markerHeight", 7)
            .attr("orient", "auto")
            .attr("fill", "#7e7878")
            .append("svg:path")
            .attr("d", "M0,-5L10,0L0,5");


        var links = g.append("g")
            .attr("stroke", "#ebebeb")
            .attr("stroke-width", 2)
            .selectAll("polyline")
            .data(response.links)
            .enter().append("polyline")
            .attr("points", function(d) {
                return [
                    d.source.x, d.source.y,
                    d.source.x/2+d.target.x/2, d.source.y/2+d.target.y/2,
                    d.target.x, d.target.y
                ].join(',');
            })
            .style("marker-mid", "url(#arrow)");

        var nodes = g.selectAll("foreignObject")
            .data(response.nodes)
            .enter()
            .append("foreignObject")
            .attr("x", function(d) {
                return d.x - nodeWidth / 2;
            })
            .attr("y", function(d) {
                return d.y - nodeHeight / 2;
            })
            .attr("width", nodeWidth)
            .attr("height", nodeHeight)
            .attr("class", function(d) {
                return ("graphNode "+d.group)
            })
            .style("background-color", function(d) {
                return "#fffefe";
            })
            .append("xhtml:div")
            .attr("class", function(d) {
                if (d.firstNode !== undefined) {
                    return "graphNodeDiv graphFirstNode";
                } else {
                    return "graphNodeDiv";
                }
            })
            .html(function(d) {
                var nodeHtml = createNodeElement(d);
                var firstNodeClass = "";
                return nodeHtml.outerHTML;
            })
            .on("click", function(d) {
                renderPopupWindow(d, "#outputWrapperFlowchart");
            })
            .append("img")
                .attr("class", "optionsImg")
                .attr("src","/images/options-squares.svg")
                .on("click", function(d) {
                    currentTooltipObject = d;
                    renderTooltipDiv();
                });

        // Define the div for the tooltip
        var toolTip = d3.select("#outputWrapperFlowchart").append("div")
            .attr("class", "tooltip")
            .attr("id", "tooltip")
            .style("display", "none")
            .style("opacity", 1);

        // Add drag capabilities
        var drag_handler = d3.drag()
            .on("start", drag_start)
            .on("drag", drag_drag)
            .on("end", drag_end);

        drag_handler(nodes);

        // Add zoom capabilities
        var zoom_handler = d3.zoom()
                .on("zoom", zoom_actions);
        zoom_handler(graphSvg);

        // Drag functions
        function drag_start(d) {
            if (!d3.event.active) simulation.alphaTarget(0.3).restart();
                d.fx = d.x;
                d.fy = d.y;
        }

        // Make sure you can't drag the circle outside the box
        function drag_drag(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }

        function drag_end(d) {
            if (!d3.event.active) simulation.alphaTarget(0);
                d.fx = null;
                d.fy = null;
            }

        //Zoom functions
        function zoom_actions(){
            g.attr("transform", d3.event.transform)
        }

        function renderTooltipDiv() {
            event.stopPropagation();
            toolTip.transition()
                .duration(200)
                .style("opacity", .9);
            toolTip
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 28) + "px");
            jQuery(".tooltip").empty();
            toolTip.append("div").attr("class", "optionsActionWrapper").attr("id", "optionActionWrapperRedraw").append("div").attr("class", "optionText").text("Redraw");
            toolTip.append("div").attr("class", "optionsActionWrapper").attr("id", "optionActionWrapperModify").append("div").attr("class", "optionText").text("Modify");
            toolTip.append("div").attr("class", "optionsActionWrapper").attr("id", "optionActionWrapperRemove").append("div").attr("class", "optionText").text("Remove");
            jQuery("#optionActionWrapperRedraw").prepend("<img class=\"optionsIcon\" src=\"/images/redraw-icon.svg\">");
            jQuery("#optionActionWrapperModify").prepend("<img class=\"optionsIcon\" src=\"/images/modify-icon.svg\">");
            jQuery("#optionActionWrapperRemove").prepend("<img class=\"optionsIcon\" src=\"/images/remove-icon.svg\">");
            tooltipState = true;
            jQuery(".tooltip").css("display", "block");
        }
    });
}

Am I doing something wrong, or can I bypass this (most likely) bug somehow?


回答1:


the bug is resulted by chrome hardware acceleration. When i disabled the feature, it works fine. But, it is not good idea. Even my case doesn't use d3 forceSimulation, you can try to give the line "fill" style with value "transparent". It works for my case.



来源:https://stackoverflow.com/questions/58997729/chrome-svg-rendering-issues-d3-polylines

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!