重复使用图表脚本

时间:2017-07-20 12:41:32

标签: javascript d3.js

我正在尝试使用具有不同数据的相同脚本在同一页面上创建3个响应式条形图。

调整窗口大小时出现问题。我一直在运行只在最后一个要渲染的图表中更新的元素。

我为没有提供jsfiddle而道歉,但我无法使用小提琴来渲染我的代码(小提琴 - 新手)

以下代码片段只生成轴'。我遇到的第一个问题是d3.axisBottom(规模) - 作为我遇到的一个例子。

页:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>AgeReport 1.3</title>

    <script src="jquery-1.11.2.js"></script>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script 
  src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js">
  </script>`

    <link rel=stylesheet type=text/css 
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-
bootstrap/3.3.5/css/bootstrap.min.css">

   <style>
       body {
           background-color: #e6e6e6;
           font-family: sans-serif;
           font-size: 12px;
       }
        section {
            position: relative;
            padding: 24px;
            height: 100%;
        }
                   .section-body:first-child {
            margin-top: 24px;
        }
                   .col-md-3, .col-lg-3, .col-md-4, .col-lg-4, .col-md-6, 
 .col-lg-6 {
            padding: 0;
        }
       .card {
          position: relative;
          background-color: #F5F5F5;
          color: #212121;
          -webkit-border-radius: 2px;
          -moz-border-radius: 2px;
          border-radius: 2px;
          border: 1px solid #BDBDBD;
          box-shadow: none;
          height: 100%;
        }
        .card-head.card-head-xs {
          line-height: 32px;
          min-height: 36px;
        }
        .card-head {
          position: relative;
          line-height: 40px;
          min-height: 44px;
          vertical-align: middle;
          border-radius: 2px 2px 0 0;
        }
       section {
           background-repeat: no-repeat;
       }
       .row {
           margin-left: 0;
       }
       .col-md-4 {
           padding-left: 5px;
           padding-right: 5px;
       }
       .card-head {
           background-color: #bdbdbd;
       }
       .card-body {
           padding: 10px 10px 10px 10px;
       }

       /*-- Age Chart --*/

       #age-chart-row {
           position: relative;
           height: 345px;
       }
       #age-chart-row .card {
           border-width: 1px 1px 0 1px;
       }
       .chart-container {
           height: 288px;
           border: 1px solid #bcbcbc;
           background-color: white;
       }
       .age-chart-canvas {
           position: absolute;
           width: 100%;
            height: 100%;
       }
        .axis--y .tick line {
            stroke: lightgray;
        }

    </style>

    <script type="text/javascript">

        var ageDistributionData = {....}'

        $(document).ready(function() {

            var vData = ageDistributionData;
            var dData = ageDistributionData;
            var mData = ageDistributionData;

            var vChart = new AgeChart("#vChart", vData);
            var dChart = new AgeChart("#dChart", dData);
            var mChart = new AgeChart("#mChart", mData);

        });

    </script>
</head>

<body>
    <section>
        <div class="section-body">
            <div id="age-chart-row" class="row">
                <div class="col-md-4">
                    <div class="card">
                        <div class="card-head card-head-xs"></div>
                        <div class="card-body">
                            <div id="vChart" class="chart-container"></div>
                        </div>
                    </div>
                </div>
                <div class="col-md-4">
                    <div class="card">
                        <div class="card-head card-head-xs"></div>
                        <div class="card-body">
                            <div id="dChart" class="chart-container"></div>
                        </div>
                    </div>
                </div>
                <div class="col-md-4">
                    <div class="card">
                        <div class="card-head card-head-xs"></div>
                        <div class="card-body">
                            <div id="mChart" class="chart-container"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>
</body>
</html>

图表脚本:

function AgeChart(container, data) {

var containerW, containerH, chartW, chartH, svg, chartG,
    xScale, x, y, gAxis, xAxis, yAxis, xBottom, bars;
var margin = {top: 20, right: 10, bottom: 50, left: 60};

//-- axis labels -> will need translating --
var yLabelStr = "Anzahl",
    xLabelStr = "Alter";

// parse raw data
var agedData = parseAgedData(data),
    sizeMax = data.AgeDistribution.DataOwnerSizeMax,
    countMax = 0;
    for (var i = 0; i < agedData.length; i++) {
        if(agedData[i].doCount > countMax) {
            countMax = agedData[i].doCount;
        }
    };

// init scales
var xScale = d3.scaleBand()
    .paddingInner(0.16)
    .paddingOuter(0.1);
xScale.domain(agedData.map(function (d) {
    return d.label;
}));
x = d3.scaleBand()
    .paddingInner(0.16)
    .paddingOuter(0.1);
x.domain(agedData.map(function (d, i) {
    return i + 1;
}));
y = d3.scaleLinear();
y.domain([0, countMax]);

// init containers
svg = d3.select(container)
    .append("svg")
    .attr("id", container.substring(1) + "Svg")
    .classed("age-chart-canvas", true);
chartG = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// init axis lines
yAxis = chartG.append("g")
    .attr("class", "axis axis--y");
gAxis = chartG.append("g")
    .attr("class", "axis axis--x");
xAxis = gAxis.append("line")
    .style("stroke", "black")
    .attr("x1", 0)
    .attr("x2", 0)
    .classed("x-domain", true);

// render chart
render();

function render() {

    updateDimensions();

    // set tick lines
    yAxis.call(d3.axisLeft(y))
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", "0.71em")
        .attr("text-anchor", "end")
        .text(function(d) {
            return d;
        });
    d3.selectAll("g.axis--y g.tick line")
        .attr("x1", function(d) {
            return chartW;
        });
    gAxis.attr("transform", "translate(0," + chartH + ")")
        .call(new d3.axisBottom(xScale));
    gAxis.selectAll(".domain").remove();
    d3.selectAll(".x-domain")
        .attr("x2", function(d) {
            return chartW;
        });

    d3.selectAll("g.axis--x g.tick line")
        .attr("y2", function(d, i) {
            if(i%2 == 0)
                return 6;
            else
                return 16;
        })
        .style("fill", "#bdbdbd");
    d3.selectAll("g.axis--x g.tick text")
        .attr("y", function(d, i) {
            if(i%2 == 0)
                return 9;
            else
                return 20;
        });

};

function updateDimensions() {
    containerW = getDimension(container, "width");
    containerH = getDimension(container, "height");
    chartW = containerW - margin.left - margin.right;
    chartH = containerH - margin.top - margin.bottom;

    // set axis scales
    xScale.rangeRound([0, chartW]);
    x.rangeRound([0, chartW]);
    y.rangeRound([chartH, 0]);
};

d3.select(window).on("resize", render);

};

谢谢!

2 个答案:

答案 0 :(得分:1)

我也被困在同一个问题上。我知道你找到了一个解决方案,但我想我会提供我发现的内容以防止其他人最终访问此页面,因为这个问题比我发现的任何其他内容更准确地描述了我的问题。 / p>

我的解决方案最终来自以下Stack Overflow帖子。答案解释了您需要向侦听器添加命名空间,否则在添加新侦听器时将删除现有侦听器。

How to have multiple d3 window resize events

对于这个例子,我不得不改变这段代码:

    d3.select(window).on("resize", render);

    var resizeId = "resize." + scope.chartId
    d3.select(window).on(resizeId, render);

其中scope.chartId是每个图表的唯一ID,因此侦听器也是唯一的,并且在添加新图表时不会被删除。

答案 1 :(得分:0)

我似乎找到了解决方案。在剔除Javascript对象后,我重新编写了我的代码来创建并返回一个封装图表属性和方法的图表对象。然后我可以在多个图表对象中调用render方法来单独更新它们。

新图表脚本:

function AgeChart(chartContainer, data) {

    var chartObj = {

    // public properties
    xAxisLabel: "Alter",
    yAxisLabel: "Anzahl",
    margin: {top: 20, right: 10, bottom: 50, left: 60},
    width: 0,
    height: 0,
    dummyData: 0,
    sizeMax: 0,
    countMax: 0,

    // private properties
    $chartGroup: 0,
    $container: "",
    $d: 0,
    $svg: 0,
    $x: d3.scaleBand()
        .paddingInner(0.16)
        .paddingOuter(0.1),
    $xscale: d3.scaleBand()
        .paddingInner(0.16)
        .paddingOuter(0.1),
    $y: d3.scaleLinear(),
    $xAxis: 0,
    $yAxis: 0,

    // property sets
    get data() { return this.$d; },
    set data(d) {
        this.$d = d;
        this.dummyData = parseAgedData(d);
        this.sizeMax = d.AgeDistribution.DataOwnerSizeMax;
        for (var i = 0; i < this.dummyData.length; i++) {
            if(this.dummyData[i].doCount > this.countMax) {
                this.countMax = chartObj.dummyData[i].doCount;
            }
        };
        this.$xscale.domain(this.dummyData.map(function(d) {
            return d.label;
        }));
        this.$x.domain(this.dummyData.map(function(d,i) {
            return i + 1;
        }))
        this.$y.domain([0, this.countMax]);
    },
    get container() { return this.$container },
    set container(c) {
        this.$container = c;
        updateDimensions();
        this.$svg = d3.select(this.container)
            .append("svg")
            .attr("id", chartObj.container.substring(1) + "Svg")
            .classed("age-chart-canvas", true);
        this.$chartGroup = this.$svg.append("g")
            .attr("transform", "translate(" + this.margin.left + "," + this.margin.top + ")");
        this.$yAxis = this.$chartGroup.append("g")
            .attr("class", "axis axis--y");
        this.$xAxis = this.$chartGroup.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0," + this.height + ")");
    },

    // methods
    render: function() {

        updateDimensions();

        this.$xscale.rangeRound([0, this.width]);
        this.$x.rangeRound([0, this.width]);
        this.$y.rangeRound([this.height, 0]);
        this.$yAxis.call(d3.axisLeft(this.$y))
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", "0.71em")
            .attr("text-anchor", "end")
            .text(function(d) {
                return d;
            });
        var chartW = this.width;
        d3.selectAll("g.axis--y g.tick line")
            .attr("x1", function(d) {
                return chartW;
            });
        this.$xAxis.call(d3.axisBottom(this.$xscale));
        d3.selectAll("g.axis--x g.tick line")
            .attr("y2", function(d, i) {
                if(i%2 == 0)
                    return 6;
                else
                    return 16;
            })
            .style("fill", "#bdbdbd");
        d3.selectAll("g.axis--x g.tick text")
            .attr("y", function(d, i) {
                if(i%2 == 0)
                    return 9;
                else
                    return 20;
            });

       }
    };

    chartObj.data = data;
    chartObj.container = chartContainer;
    chartObj.render();

    function updateDimensions() {

        var containerW = getDimension(chartObj.container, "width"),
        containerH = getDimension(chartObj.container, "height");
        chartObj.width = containerW - chartObj.margin.left -   
        chartObj.margin.right;
        chartObj.height = containerH - chartObj.margin.top -   
        chartObj.margin.bottom;

   };

    return chartObj;

};

然后在我的页面上,当调整窗口大小并且所有图表都独立更新时,我调用render()...

    <script type="text/javascript">

        $(document).ready(function() {

            var vData = ageDistributionData;
            var dData = ageDistributionData;
            var mData = ageDistributionData;

            var vChart = AgeChart("#vChart", vData);
            var dChart = new AgeChart("#dChart", dData);
            var mChart = new AgeChart("#mChart", mData);

            window.addEventListener("resize", function() {
                vChart.render();
                dChart.render();
                mChart.render();
            })

        });

    </script>

欢迎任何提示或建议。