将D3.js元素附加到Polymer Element的Shadow DOM

时间:2017-03-31 21:32:25

标签: d3.js polymer shadow-dom

我正在研究Polymer(v1)项目,我的一个定制聚合物元素需要包含D3(v4)图表。 D3似乎在追加DOM时非常重视。不幸的是,Polymer似乎对如何执行DOM操作非常严格。

我创建了一个非常简单的D3图表版本:

的index.html

<!DOCTYPE html>
<html>
<head>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <style>
        .bar {
            fill: #0198E1;
        }
    </style>
</head>
<body>

<svg></svg>

<script>
var data = [100, 120, 130, 110, 150, 90];

const CHART_WIDTH = 126;
const CHART_HEIGHT = 160;

svg = d3.select('svg')
    .attr("width", CHART_WIDTH)
    .attr("height", CHART_HEIGHT);

svg.selectAll('rect')
    .data(data).enter().append('rect')
        .attr("x", function(d, i) {return i * 21})
        .attr("y", function(d) {return CHART_HEIGHT - d})
        .attr("height", function(d) {return d})
        .attr("width", 20)
        .attr("class", "bar");
</script>
</body>
</html>

我尝试了两个包含以下文件的解决方案。

的index.html

<!DOCTYPE html>
<html>
<head>
    <link rel="import" href="../bower_components/polymer/polymer.html">
    <link rel="import" href="./d3-chart.html">
</head>
<body>
    <d3-chart></d3-chart>
</body>
</html>

D3-lib.html

<script src="https://d3js.org/d3.v4.min.js"></script>

尝试解决方案1 ​​

使用D3和Polymer的组合来选择目标svg元素,然后执行d3追加。

D3-chart.html

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="./d3-lib.html">

<dom-module id="d3-chart">
    <template>
        <style>
           .bar {
               fill: #0198E1;
           }
        </style>

        <svg id="svg"></svg>
    </template>

    <script>
        Polymer({
            is: 'd3-chart',
            properties: {
                data: {
                    Type: Array,
                    value: [100, 120, 130, 110, 150, 90]
                }
            },
            ready: function() {
                const CHART_WIDTH = 126;
                const CHART_HEIGHT = 160;

                var svg = d3.select(this.$.svg)
                    .attr("width", CHART_WIDTH)
                    .attr("height", CHART_HEIGHT);

                svg.selectAll('rect')
                    .data(this.data).enter().append('rect')
                        .attr("x", function(d, i) {return i * 21})
                        .attr("y", function(d) {return CHART_HEIGHT - d})
                        .attr("height", function(d) {return d})
                        .attr("width", 20)
                        .attr("class", "bar");
            }
        });
    </script>
</dom-module>

这会成功显示图表,但css样式不适用。我认为这是因为Polymer不知道已附加的新元素。

尝试解决方案2

使用D3选择新的svg元素(不在DOM中),在元素上执行D3附加,并使用Polymer将其附加到DOM。

D3-chart.html

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="./d3-lib.html">

<dom-module id="d3-chart">
    <template>
        <style>
           .bar {
               fill: #0198E1;
           }
        </style>

    </template>

    <script>
        Polymer({
            is: 'd3-chart',
            properties: {
                data: {
                    Type: Array,
                    value: [100, 120, 130, 110, 150, 90]
                }
            },
            ready: function() {
                const CHART_WIDTH = 126;
                const CHART_HEIGHT = 160;

                var newSvgElement = document.createElement("svg");

                var svg = d3.select(newSvgElement)
                    .attr("width", CHART_WIDTH)
                    .attr("height", CHART_HEIGHT);

                svg.selectAll('rect')
                    .data(this.data).enter().append('rect')
                        .attr("x", function(d, i) {return i * 21})
                        .attr("y", function(d) {return CHART_HEIGHT - d})
                        .attr("height", function(d) {return d})
                        .attr("width", 20)
                        .attr("class", "bar");

                Polymer.dom(this.root).appendChild(newSvgElement);
            }
        });
    </script>
</dom-module>

此代码成功地将所有元素附加到DOM,但不显示任何内容。

将聚合物与D3整合的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

我找到了解决方案。我只需要在'尝试解决方案1'中将以下行添加到ready函数的开头。

this.scopeSubtree(this.$.svg, true);

了解更多信息: Why is my SVG rendered by D3 inside a Polymer component unstyled?