Javascript 加载数据一次,但使用全局变量“是否是一种良好的做法?”;var数据&引用;

Javascript 加载数据一次,但使用全局变量“是否是一种良好的做法?”;var数据&引用;,javascript,d3.js,Javascript,D3.js,我是js新手,读到关于变量的使用、各自的范围以及隐藏数据的方式,有“隐藏在阴影中的怪物” 我正在使用d3.js并从csv加载数据,但我只想进行一次GET调用,因为更复杂的可视化可能涉及10个csv文件,其中一些文件包含多达10000行数据-因此我在脚本“var data;”的顶部添加了一个变量它在初始渲染时被填充,然后在用户的后续交互中使用该变量 我的方法安全吗?如果有更好的模式,我应该使用什么 BarData.csv如下所示: Fruit,dt,amount Apple,12/28/2016,

我是js新手,读到关于变量的使用、各自的范围以及隐藏数据的方式,有“隐藏在阴影中的怪物”

我正在使用d3.js并从csv加载数据,但我只想进行一次GET调用,因为更复杂的可视化可能涉及10个csv文件,其中一些文件包含多达10000行数据-因此我在脚本“var data;”的顶部添加了一个变量它在初始渲染时被填充,然后在用户的后续交互中使用该变量

我的方法安全吗?如果有更好的模式,我应该使用什么

BarData.csv如下所示:

Fruit,dt,amount
Apple,12/28/2016,-1256
Apple,12/29/2016,-500
Apple,12/30/2016,3694
Apple,12/31/2016,5586
Apple,1/1/2017,4558
Apple,1/2/2017,6696
Apple,1/3/2017,7757
Apple,1/4/2017,8528
Apple,1/5/2017,5543
Apple,1/6/2017,3363
Apple,1/7/2017,5464
Pear,12/25/2017,250
Pear,12/26/2017,669
Pear,12/27/2017,441
Pear,12/28/2017,159
Pear,12/29/2017,357
Pear,12/30/2017,775
Pear,12/31/2017,669
代码都在一个
html
文件中,如下所示:

<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <title>BAR SINGLE FUNCTION</title>
  <script src="http://d3js.org/d3.v3.js"></script>
  <style type="text/css">
    #radioDiv {
      top: 45px;
      font-family: verdana;
      font-size: 8px;
      width: 455px;
    }

    #TOPbarChart {
      position: absolute;
      top: 50px;
      left: 30px;
      width: 750px;
      height: 195px;
    }

    .axis--y path,
    .axis--x path {
      display: none;
    }

    .axis--x line,
    .axis--y line {
      stroke: black;
      fill: none;
      stroke-width: 2px
    }

    .yAxis text,
    .xAxis text {
      font: 7pt Verdana;
      stroke: none;
      fill: black;
    }

    .title,
    .titleX {
      font-family: Verdana;
      font-size: 10px;
    }
  </style>
</head>

<body>
  <div id="radioDiv">
    <label>
      <input id="radioFrt" type="radio" name="frt" value="Apple" class="radioB" checked> APPLE
    </label>
    <label>
      <input type="radio" name="frt" value="Pear" class="radioB"> PEAR
    </label>
  </div>
  <div id="TOPbarChart"></div>
  <script type="text/javascript">
    var currentFruit = "Apple";
    var currentColr = "#00a5b6";

    var barDataCSV_Dly = "BarData.csv";

    var data;
    //
    //
    // radio button
    document.getElementById("radioFrt").checked = true;
    d3.selectAll('input[name="frt"]').on("change", function change() {
      currentFruit = this.value;
      //load();
      TOPbarChart(currentFruit, currentColr);
    });

    //FORMATS 
    var parseDate = d3.time.format("%m/%d/%Y").parse;



    // 
    // BASIC SIZING
    // 
    function barChartBasics() {
      var margin = {
          top: 25,
          right: 35,
          bottom: 25,
          left: 70
        },
        width = 550 - margin.left - margin.right,
        height = 155 - margin.top - margin.bottom,
        colorBar = d3.scale.category20(),
        barPaddingFine = 1,
        barPaddingThick = 2;
      return {
        margin: margin,
        width: width,
        height: height,
        colorBar: colorBar,
        barPaddingFine: barPaddingFine,
        barPaddingThick: barPaddingThick
      };
    }


    // create svg element
    var basics = barChartBasics();
    var svg = d3.select("#TOPbarChart")
      .append("svg")
      .attr({
        "width": basics.width + basics.margin.left + basics.margin.right,
        "height": basics.height + basics.margin.top + basics.margin.bottom,
        id: "svgTOPbarChart"
      });

    // create svg  group
    var plot = svg
      .append("g")
      .attr({
        "transform": "translate(" + basics.margin.left + "," + basics.margin.top + ")",
        id: "svgPlotTOPbarChart"
      });

    var axisPadding = 2;
    var leftAxisGroup = svg
      .append('g')
      .attr({
        transform: 'translate(' + (basics.margin.left - axisPadding) + ',' + (basics.margin.top) + ')',
        'class': "yAxis axis--y",
        id: "yAxisGTOPbarChart"
      });

    var bottomAxisGroup = svg
      .append('g')
      .attr({
        'class': "xAxis axis--x",
        id: "xAxisGTOPbarChart"
      });

    var titleTxt = svg.append("text")
      .attr({
        x: basics.margin.left + 12,
        y: 20,
        'class': "title",
        'text-anchor': "start"
      })

    // create scales with ranges
    var xScale = d3.time.scale().range([0, basics.width]);
    var yScale = d3.scale.linear().range([basics.height, 0]);




   function load(){
     d3.csv(barDataCSV_Dly, function(rows) {
        data = rows;
        TOPbarChart(currentFruit, currentColr)
     })
   }


    function TOPbarChart(
      frt, colorChosen) {

      // get the data
      //d3.csv(barDataCSV_Dly, function(rows) {

        TOPbarData = data.map(function(d) {
          return {
            "Fruit": d.Fruit,
            "dt": parseDate(d.dt),
            "amount": +d.amount
          };
        }).filter(function(row) {
          if (row['Fruit'] == frt) {
            return true;
          }
        });


        // create domains for the scales
        xScale.domain(d3.extent(TOPbarData, function(d) {
          return d.dt;
        }));
        var amounts = TOPbarData.map(function(d) {
          return d.amount;
        });
        var yMax = d3.max(amounts);
        var yMin = d3.min(amounts);
        var yMinFinal = 0;
        if (yMin < 0) {
          yMinFinal = yMin;
        }



        yScale.domain([yMinFinal, yMax]);


        // introduce the bars
        // var plot = d3.select("#svgPlotTOPbarChart")
        var sel = plot.selectAll("rect")
          .data(TOPbarData);

        sel.enter()
          .append("rect")
          .attr({
            x: function(d, i) {
              return xScale(d.dt);
            },
            y: function(d) {
              return yScale(Math.max(0, d.amount));
            },
            width: (basics.width / TOPbarData.length - basics.barPaddingFine),
            height: function(d) {
              return Math.abs(yScale(d.amount) - yScale(0));
            },
            //fill: colorChosen,
            fill: function(d, i) {
              return d.amount < 0 ? "#FF0000" : colorChosen;
            },
            // fill: function(d, i) {
            //            var col = colorChosen
            //              if (d.amount < 0) {
            //                col = "#FF0000";
            //            }
            //            return col;
            //        },
            'class': "bar"
          });

        // this little function will create a small ripple affect during transition
        var dlyRipple = function(d, i) {
          return i * 100;
        };

        sel
          .transition()
          .duration(dlyRipple) //1000
          .attr({
            x: function(d, i) {
              return xScale(d.dt);
            },
            y: function(d) {
              return yScale(Math.max(0, d.amount));
            },
            width: (basics.width / TOPbarData.length - basics.barPaddingFine),
            height: function(d) {
              return Math.abs(yScale(d.amount) - yScale(0));
            },
            //fill: colorChosen
            fill: function(d, i) {
              var col = colorChosen
              if (d.amount < 0) {
                col = "#FF0000";
              }
              return col;
            },
          });

        sel.exit().remove();


        // add/transition y axis - with ticks and tick markers
        var axisY = d3.svg.axis()
          .orient('left')
          .scale(yScale)
          .tickFormat(d3.format("s")) // use abbreviations, e.g. 5M for 5 Million
          .outerTickSize(0);
        leftAxisGroup.transition().duration(1000).call(axisY);

        // add/transition x axis - with ticks and tick markers
        var axisX = d3.svg.axis()
          .orient('bottom')
          .scale(xScale);

        bottomAxisGroup
          .attr({
            transform: 'translate(' + (basics.margin.left + ((basics.width / TOPbarData.length) / 2)) + ',' + (basics.margin.top + basics.height) + ')',
          })
          .transition().duration(1000).call(axisX.ticks(5));


        titleTxt.text("Daily: last " + TOPbarData.length + " days");
        // console.log(TOPbarData.length)

      //});
    }

    //
    //
    //
    //
    load()
    //TOPbarChart(currentFruit, currentColr);
    //
    //
    //
    //
  </script>
</body>

</html>
在随后的函数中,我有以下内容:

var x = Module_BarDataDaily.dataX;

TOPbarData = x.map(function(d) {  /<<< Type error x is undefined
    return {
...
var x=Module\u BarDataDaily.dataX;

TOPbarData=x.map(函数(d){/在变量中缓存记录并不坏,除非它是私有的,并且在脚本中的任何其他地方都不可见

您当前的方法在全局名称空间中设置
数据
变量,基本上,如果您包含的任何其他插件也包含名为
数据
的变量,则可能会覆盖其值。-这是不安全的

要向世界其他地方隐藏变量,您可能希望在自调用函数中包含所有代码:

(function() {
  var data = ...; // It's accessible only in that function

  // Your JavaScript code

})();
相关说明:


如果要在文件之间共享变量,请在对象(称为模块)内执行,例如:

JavaScript提供了类似于Python的内置模块系统,但是浏览器还不支持它

相关说明:



PS:将CSS和JavaScript与外部文件分开以避免混乱。

在更新您的问题后,还有一个问题称为
异步数据

库函数
d3.csv(…)
与其他计算异步工作,这意味着您永远无法确定
数据是否已填充。它可能是立即填充的,也可能是几秒钟后填充的

这就是为什么
x是未定义的
,因为在解析该代码时,
d3.csv
尚未完成计算

处理此代码的最简单尝试是使用
回调
函数。 基本上,您的模块返回函数
loadData
,该函数接受函数,只有当模块知道
data
已填充时才会调用该函数

var Module_BarDataDaily = (function() {
    var data;

    return {
        loadData: lazyLoadData
    };

    function lazyLoadData(callback) {
        if (data) {
            callback(data); // data already exists, run function
        } else {
            d3.csv("myData.csv", function(rows) {
                data = rows;
                callback(data); // data is filled, run function
            });
        }
    }
})();
下面是如何将其用于该尝试

Module_BarDataDaily.loadData(function(data) {
    // this function loads only after data is filled
    TopChartData = data.map(...);
});
什么是回调?

简单地说,回调函数就像一个“调用 完成任务后,返回给经理

  • 资料来源:


注意:还有许多其他可能更好的解决此类问题的尝试,如ES2015中的
Promise
wait
,将与ES2017一起发布。

我不清楚您在问题主体中问了什么。标题的答案是“不,拥有一个全球性的
数据
——或者实际上,任何其他全球性的数据都不是最佳做法。”@T.J.Crowder为不够清晰表示歉意。就这一点而言,“我的方法安全吗?如果有更好的模式,我应该使用什么?“你们是说我的方法不安全……那个么什么样的方法才是最好的做法呢?我尝试了你们的建议,但得到了一个未定义的错误?我已经尝试修正了这个问题。@为什么问:这是不同的问题,所以我添加了另一个答案。希望我没有在代码中输入错误;)这是非常感谢你Piotr花时间为我添加这些额外的信息-谢谢你。
var Module_BarDataDaily = (function() {
    var data;

    return {
        loadData: lazyLoadData
    };

    function lazyLoadData(callback) {
        if (data) {
            callback(data); // data already exists, run function
        } else {
            d3.csv("myData.csv", function(rows) {
                data = rows;
                callback(data); // data is filled, run function
            });
        }
    }
})();
Module_BarDataDaily.loadData(function(data) {
    // this function loads only after data is filled
    TopChartData = data.map(...);
});